1. 程式人生 > >最小點覆蓋,二分圖最大匹配—POJ1274 POJ1469 POJ1469

最小點覆蓋,二分圖最大匹配—POJ1274 POJ1469 POJ1469

-s 要求 ini vector ++ %d () tin clas

二分圖最大匹配常用的匈牙利算法,之前寫的很幼稚,雖然也過了,但是平白的比別人多開了兩倍的空間。

本來就是在填加邊的時候把左邊的點和右邊的點分開算都加在圖裏面儲存,然後匹配的時候就互相匹配

match[u]=v; match[v]=u; 然後看了模板之後才發現其實完全不用加上,只記錄match[v]=u就可以了

三題的代碼都是一樣的,需要註意的是1469題是要求求最小點覆蓋數,最小點覆蓋數就等於最大匹配數。

簡單說下。

首先,最小點覆蓋數肯定不會小於匹配數,因為那樣連已經匹配的邊都沒法覆蓋掉,何談沒有算在匹配邊裏的邊呢。

其次,二分圖麽,可以把已經匹配的點分成兩個陣營,匹配邊的兩側,這樣,沒有匹配的點(如果有邊相連,沒有邊相連的話就不需要考慮了)

肯定會跟已經匹配的點有一條邊連起來,把這樣的匹配點放到左陣營中,並且最小覆蓋點全部都選則左陣營的已經匹配的點,那就正好是匹配邊數了。

不可能又這樣的兩個未匹配的點,兩個點分別與已經匹配的邊的兩點都有連線,如果這樣的話,那麽不如拆掉中間的匹配邊,兩兩相連,就又多了一條匹配邊。

綜上,點覆蓋數可以是最大匹配數,但不能小於最大匹配數,所以最小點覆蓋數就是最大匹配數。

//POJ 1274
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <vector>
using
namespace std; const int N = 500 + 5; const int E = 1e5 + 5; vector<int> G[N]; int n,m; int match[N],vis[N]; void init() { for(int i = 0; i < N; i++) G[i].clear(); memset(match, -1, sizeof(match)); } int dfs(int u) { for(int i = 0; i < G[u].size(); i++) {
int v = G[u][i]; if(vis[v]) continue; vis[v] = 1; if(match[v] == -1 || dfs(match[v])) { match[v] = u; return 1; } } return 0; } int main() { int num,tmp; while(scanf("%d%d", &n, &m) == 2) { init(); for(int i = 1; i <= n; i++) { scanf("%d", &num); for(int j = 0; j < num; j++) { scanf("%d", &tmp); G[i].push_back(tmp); } } int ans = 0; for(int i = 1; i <= n + m; i++) { memset(vis, 0, sizeof(vis)); ans += dfs(i); } printf("%d\n", ans); } return 0; }

最小點覆蓋,二分圖最大匹配—POJ1274 POJ1469 POJ1469