题目:http://community.topcoder.com/stat?c=problem_statement&pm=1931&rd=4709
题目的难点在于将问题抽象成最大流问题,这个题目可以看成是 最大二分图匹配问题(maximum bipartite-matching problem),行可以看成二分图中的 顶点集A,列可以看成二分图中顶点集B,下面的问题就是最大匹配A,B。使用最大流算法求解。
代码如下:
#include <algorithm> #include <functional> #include <numeric> #include <utility> #include <iostream> #include <sstream> #include <iomanip> #include <bitset> #include <string> #include <vector> #include <stack> #include <deque> #include <queue> #include <set> #include <map> #include <cstdio> #include <cstdlib> #include <cctype> #include <cmath> #include <cstring> #include <ctime> #include <climits> using namespace std; #define CHECKTIME() printf("%.2lf\n", (double)clock() / CLOCKS_PER_SEC) typedef pair<int, int> pii; typedef long long llong; typedef pair<llong, llong> pll; #define mkp make_pair /*************** Program Begin **********************/ bool cut[605][605]; // 位置是否可放置 int cap[605][605]; // 每条边的容量 int from[605]; // 保留最短路径上到达该点的上一个顶点 bool v[605]; // 访问数组 const int INF = 1000000; class RookAttack { public: int rows, cols; // 使用增广路径法求最大流,返回值为0时说明残留图中不存在增广路径 int bfs() { memset(v, 0, sizeof(v)); memset(from, -1, sizeof(from)); queue <int> Q; int start = rows, end = rows + cols + 1; // 添加两个超级顶点,将问题转化为单源单汇 Q.push(start); v[start] = true; int where; // bfs 求最短路径 bool ok = false; while (!Q.empty()) { where = Q.front(); Q.pop(); for (int i = 0; i <= rows + cols + 1; i++) { if (cap[where][i] > 0 && !v[i]) { // 有边且点未被访问 from[i] = where; v[i] = true; if (i == end) { ok = true; break; } Q.push(i); } } if (ok) { break; } } // 求最短路径上的最小容量 int path_cap = INF; where = end; while (from[where] != -1) { int pre = from[where]; path_cap = min(path_cap, cap[pre][where]); where = pre; } // 更新残留图,cap[]数组 where = end; while (from[where] != -1) { int pre = from[where]; cap[pre][where] -= path_cap; cap[where][pre] += path_cap; where = pre; } return (path_cap == INF ? 0 : path_cap); } int howMany(int rows, int cols, vector <string> cutouts) { int res = 0; this->rows = rows; this->cols = cols; memset(cut, 0, sizeof(cut)); // 对字符串进行处理 string S; for (int i = 0; i < cutouts.size(); i++) { S += cutouts[i] + ", "; } for (int i = 0; i < S.size(); i++) { if (‘,‘ == S[i]) { S[i] = ‘ ‘; } } int r, c; stringstream ss(S); // 每行、每列代表一个顶点,行顶点编号为0...rows - 1,超级源点为rows; // 列顶点编号为rows + 1 ... rows + cols,超级汇点为rows + cols + 1. while (ss >> r >> c) { cut[r][c + rows + 1] = true; } memset(cap, 0, sizeof(cap)); for (int i = 0; i < rows; i++) { for (int j = rows + 1; j < rows + cols + 1; j++) { if (!cut[i][j]) { cap[i][j] = 1; // 有边,容量为1 } cap[j][rows + cols + 1] = 1; // 每个汇点到超级汇点的容量为1 } cap[rows][i] = 1; // 超级源点到每个源点的容量为1 } int add; while ( (add = bfs()) != 0 ) { // 不断调用BFS,直到没有残留图中没有增广路径为止 res += add; } return res; } }; /************** Program End ************************/
Maximum Flow 练习:RookAttack,最大二分图匹配,布布扣,bubuko.com
Maximum Flow 练习:RookAttack,最大二分图匹配
原文:http://blog.csdn.net/xzz_hust/article/details/22090701