匈牙利算法,通过反复寻找增广路的方法求最大匹配。
1 const int MAXV = 1001; 2 int V; //顶点数 3 vector<int> G[MAXV]; //图的邻接表表示 4 int match[MAXV]; //所匹配的定点 5 bool used[MAXV]; // DFS中用到的访问标记 6 7 //添加无向边,注意顶点编号从0开始 8 void add_edge(int u, int v) { 9 G[u].push_back(v); 10 G[v].push_back(u); 11 } 12 13 //通过DFS寻找增广路 14 bool dfs(int v) { 15 used[v] = true; 16 for (int i = 0; i < G[v].size(); i++) { 17 int u = G[v][i], w = match[u]; 18 if (w < 0 || !used[w] && dfs(w)) { 19 match[v] = u; 20 match[u] = v; 21 return true; 22 } 23 } 24 return false; 25 } 26 27 //二分图最大匹配,返回最大匹配数 28 int Bipartite_Matching() { 29 int res = 0; 30 memset(match, -1, sizeof(match)); 31 for (int v = 0; v < V; v++) { 32 if (match[v] < 0) { 33 memset(used, 0, sizeof(used)); 34 if (dfs(v)) { 35 res++; 36 } 37 } 38 } 39 return res; 40 }
POJ3041
题意:
在一个N*N的网格上有K个小行星,小行星的位置是($R_i$, $C_i$),有武器一次可以摧毁或一列的小行星,问最少几次使用武器可以将小行星全部摧毁。
解法:
把光束(横、纵两种)当作顶点,把小行星的位置当作边。问题就是选若干个点(光束)覆盖所有的边,这是最小顶点覆盖(任意边都有只少一个顶点被涵盖),等效于最大匹配。
横纵两种光束是二分图,所以直接二分最大匹配即可。
代码如下:
1 const int MAXV = 1001; 2 int V; //顶点数 3 vector<int> G[MAXV]; //图的邻接表表示 4 int match[MAXV]; //所匹配的定点 5 bool used[MAXV]; // DFS中用到的访问标记 6 7 //添加无向边,注意顶点编号从0开始 8 void add_edge(int u, int v) { 9 G[u].push_back(v); 10 G[v].push_back(u); 11 } 12 13 //通过DFS寻找增广路 14 bool dfs(int v) { 15 used[v] = true; 16 for (int i = 0; i < G[v].size(); i++) { 17 int u = G[v][i], w = match[u]; 18 if (w < 0 || !used[w] && dfs(w)) { 19 match[v] = u; 20 match[u] = v; 21 return true; 22 } 23 } 24 return false; 25 } 26 27 //二分图最大匹配,返回最大匹配数 28 int Bipartite_Matching() { 29 int res = 0; 30 memset(match, -1, sizeof(match)); 31 for (int v = 0; v < V; v++) { 32 if (match[v] < 0) { 33 memset(used, 0, sizeof(used)); 34 if (dfs(v)) { 35 res++; 36 } 37 } 38 } 39 return res; 40 } 41 42 const int MAXK = 10000 + 5; 43 int N, K; 44 int R[MAXK], C[MAXK]; 45 46 int main() { 47 #ifndef ONLINE_JUDGE 48 freopen("input.txt", "r", stdin); 49 #endif // !ONLINE_JUDGE 50 N = READ(), K = READ(); 51 REP(i, 1, K) { 52 int R = READ(), C = READ(); 53 add_edge(R - 1, C + N - 1); 54 } 55 V = N + N; 56 printf("%d ", Bipartite_Matching()); 57 return 0; 58 }