一.原题链接: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());
}
}