一.原题链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1654
二.题目大意:给一个矩阵,每个格子里面有#,*,和o,分别代表墙,玻璃和空地,空地上可以放机器人,机器人的激光可以穿透玻璃不能穿透墙,激光可以横着走或竖着走,求最多可以放多少个机器人。
三.思路:乍一看,八皇后问题,直接想深搜,一格一格搜,就是求最大独立点集,但是为什么会出现在二分图匹配上呢?看了一下数据规模,50,2的50次方复杂度(233333...)
接下来说一下二分匹配建图思路:
1.将每一行相连的几个格子看作一个点,标号。记录在xs[i][j]上,空地标号,墙和玻璃标号为0。
2.将每一列相连的几个格子看作一个点,标号。记录在ys[i][j]上,如上。
3.扫一次xs[i][j],如果大于0,说明这是空地,连接xs[i][j]与ys[i][j],表示这一块空地被标号为xs[i][j]的行(点)和标号为ys[i][j]的列(点)占用(ys[i][j]肯定也会大于0)。当然会出现连多次,但这是不带权的没关系。
建图过程就完了,求得的最大匹配数,就是机器人可以放置数。
概念扫盲:
匹配:就是独立边集,任意2条边不相邻。
最大匹配:最大独立边集。
求出来的表示行和列都被占用的块,只能填一个机器人。
二分图最大匹配算法:匈牙利算法
二分图点集被分为X和Y,扫描X中的每一个x,没有匹配的话,就在Y中去找一个没有被匹配的y。
1.找不到和x相连的,在X中继续找下一个。
2.找到和x相连的,但是被匹配了,让那个已经被匹配的x'去找别的y匹配,当前x占它的位置。
四.代码:
#include <iostream> #include <cstdio> #include <queue> #include <cstring> #include <cstdlib> using namespace std; const int INF = 0x3f3f3f3f, MAX_SIZE = 58; class maxMatch { public: bool weight[MAX_SIZE*MAX_SIZE][MAX_SIZE*MAX_SIZE], visited[MAX_SIZE*MAX_SIZE]; int xMatch[MAX_SIZE*MAX_SIZE], yMatch[MAX_SIZE*MAX_SIZE], numX, numY; void init() { numX = 0, numY = 0; memset(weight, 0, sizeof(weight)); } bool path(int u) { int v; for(v = 1; v <= numY; v++) if(weight[u][v] && !visited[v]){ visited[v] = true; if(-1 == yMatch[v] || path(yMatch[v])){ yMatch[v] = u; xMatch[u] = v; return true; } } return false; } int getRes() { int i, j, res; memset(xMatch, -1, sizeof(xMatch)); memset(yMatch, -1, sizeof(yMatch)); res = 0; for(i = 1; i <= numX; i++) if(-1 == xMatch[i]){ memset(visited, 0, sizeof(visited)); if(path(i)) res++; } return res; } }G; int xs[MAX_SIZE][MAX_SIZE], ys[MAX_SIZE][MAX_SIZE], row, col; char mp[MAX_SIZE][MAX_SIZE]; void buildG() { int i, j, num = 0; bool flag; for(i = 0; i < row; i++){ flag = false; for(j = 0; j < col; j++) if('o' == mp[i][j]){ if(!flag) num++; xs[i][j] = num; flag = true; } else{ xs[i][j] = 0; if('#' == mp[i][j]) flag = false; } } G.numX = num; num = 0; for(j = 0; j < col; j++){ flag = false; for(i = 0; i < row; i++) if('o' == mp[i][j]){ if(!flag) num++; ys[i][j] = num; flag = true; } else{ ys[i][j] = 0; if('#' == mp[i][j]) flag = false; } } G.numY = num; for(i = 0; i < row; i++) for(j = 0; j < col; j++) if(xs[i][j]) G.weight[xs[i][j]][ys[i][j]] = true; } int main() { //freopen("in.txt", "r", stdin); int test, i, kase = 1; scanf("%d", &test); while(test--){ G.init(); scanf("%d%d", &row, &col); for(i = 0; i < row; i++) scanf("%s", mp[i]); buildG(); printf("Case :%d\n%d\n", kase++, G.getRes()); } }