Maximum Flow 练习:RookAttack,最大二分图匹配

来源:互联网 发布:人工智能英语作文话题 编辑:程序博客网 时间:2024/05/17 04:37

题目: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 ************************/

如果使用dfs来找最短路径的话,代码更简洁,如下:

#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[305][305];// 位置是否可放置int col_match[305];bool v[305];// 访问数组class RookAttack {public:int rows, cols;int find_path(int where){if (-1 == where) {// 找到一条增广路return 1;}for (int i = 0; i < cols; i++) {if (cut[where][i] || v[i]) {continue;}v[i] = true;if (find_path(col_match[i])) {col_match[i] = where;// 相当于更新残留图return 1;}}return 0;}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);while (ss >> r >> c) {cut[r][c] = true;}memset(col_match, -1, sizeof(col_match));for (int i = 0; i < rows; i++) {memset(v, 0, sizeof(v));res += find_path(i);// dfs找增广路径}return res;}};/************** Program End ************************/


3 0
原创粉丝点击