关于匈牙利算法的描述可以去看 http://blog.csdn.net/winoros/article/details/18949489
下面贴出题目的description
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 7533 | Accepted: 2778 |
Description
大意就是在一个n * m的图中,有一些地方是要加上遮挡物的,遮挡物可以横着放,可以竖着放,长度不限。要求找到遮挡物放置的最小数目。
这里用到了一种构建二分图的方法,就是以原图中的边为二分图中的点,横边在一个集合中,纵边在一个集合中,而原图中的点则作为二分图中的边,用于连接两个集合中的点(原来的边)。
对该题使用上述构图法的话,那么则是那些需要遮挡物的横边和纵边为两个集合中的点。
对于题目中给出的样例(*代表方块需要被遮挡)来说就是
分别作为两个集合中的点(我的代码中边是从0开始标号的), 而横边和纵边相交的点就是所建二分图中的边。
那么所求便是二分图的最小顶点覆盖,可以转化为用匈牙利算法求最大匹配。
具体对边标号的方法可以看我的代码。
(对了这个题有个蛋疼的地方,就是二分图最多会有多少个点。。。我个人认为是625,就是25*25.。。。不过代码是建了500大小的数组过去的。。。)
(再P.S. 在题目的discuss里有说数组要开900多。。。我是没有理解。。。)
// by winoros 184K 16MS C++ #include <iostream> #include <cstdlib> #include <cstdio> #include <string> #include <cstring> #include <numeric> #include <algorithm> #include <vector> #include <stack> #include <queue> #include <utility> #define max(a,b) ((a)>(b))?(a):(b) #define min(a,b) ((a)>(b))?(b):(a) #define rep(i,initial_n,end_n) for(int (i)=(initial_n);(i)<(end_n);i++) #define repp(i,initial_n,end_n) for(int (i)=(initial_n);(i)<=(end_n);(i)++) #define reep(i,initial_n,end_n) for((i)=(initial_n);(i)<(end_n);i++) #define reepp(i,initial_n,end_n) for((i)=(initial_n);(i)<=(end_n);(i)++) #define eps 1.0E-9 #define MAX_N 1010 #define INF 1<<30 using namespace std; typedef pair<int, int> pii; typedef long long ll; typedef unsigned long long ull; vector<int> v[500]; int pre[500]; bool flag[500]; int atlas[55][55]; bool find(int x); int hungary(int n); int main() { int n, m, cur = 0; char tmp; scanf("%d%d", &n, &m); getchar(); //读入数据,并对横边标号 rep(i, 0, n) { rep(j, 0, m) { scanf("%c", &tmp); if(tmp == '.') atlas[i][j] = -1; else if(j == 0 || atlas[i][j - 1] == -1) atlas[i][j] = cur++; else atlas[i][j] = atlas[i][j - 1]; } getchar(); } //对纵边标号,并建二分图 int curr = -1; rep(j, 0, m) { rep(i, 0, n) { if(atlas[i][j] == -1) continue; else if(i == 0 || atlas[i - 1][j] == -1) v[atlas[i][j]].push_back(++curr); else v[atlas[i][j]].push_back(curr); } } printf("%d\n", hungary(cur)); return 0; } bool find(int x) { int len = v[x].size(); rep(i, 0, len) { if(!flag[v[x][i]]) { flag[v[x][i]] = true; if(pre[v[x][i]] == -1 || find(pre[v[x][i]])) { pre[v[x][i]] = x; return true; } } } return false; } int hungary(int n) { int ans = 0; memset(pre, 255, sizeof(pre)); rep(i, 0, n) { memset(flag, 0, sizeof(flag)); if(find(i)) ans++; } return ans; }