题意:给一个地图,分空地o 草地* 和墙壁#,可以在空地上放 向上下左右四个方向放激光【激光能穿过草无法穿墙】的机器人,问最多能放多少这样的机器人
题解:原理跟poj上那个 ”在一个点上放了以后该行该列都没发放“的原理是一样的
poj那道题是 每一行,每一列都算一块,然后X行和Y列的 交点【放置机器人的位置】就是 x-y 这条边
而这题有墙,所以 把每行和列都按照墙的分割,然后将 分块后的行列 连边【当他们的交点为空地时】
最后求一下最大匹配
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2505;
#define _clr(x) memset(x, 0xff, sizeof(int) * MAXN)
int mk[MAXN], match1[MAXN], match2[MAXN], mat[MAXN][MAXN], n, m;
int path(int i){
for (int j = 0; j < m; j++)
if (mat[i][j] && !(mk[j]++) && (match2[j] < 0 || path(match2[j]))){
match1[i] = j;
match2[j] = i;
return 1;
}
return 0;
}
int hungary(){
int res(0);
_clr(match1);
_clr(match2);
for (int i = 0; i < n; i++)
if (match1[i] < 0){
memset(mk, 0, sizeof(mk));
res += path(i);
}
return res;
}
int nn,mm;
char s[100][100];
int xx[100][100],yy[100][100];
void Gao()
{
memset(mat,0,sizeof(mat));
memset(xx,0,sizeof(xx));
memset(yy,0,sizeof(yy));
cin>>nn>>mm;
for (int i=0;i<nn;i++)
scanf("%s",s[i]);
int numx=0,numy=0;
for (int i=0;i<nn;i++)
{
bool line=false;
for (int j=0;j<mm;j++)
{
if (s[i][j]!='#')
{
if (!line)
numx++;
line=true;
xx[i][j]=numx;
}
if (s[i][j]=='#')
line=false;
}
}
for (int j=0;j<mm;j++)
{
bool line=false;
for (int i=0;i<nn;i++)
{
if (s[i][j]!='#')
{
if (!line)
numy++;
line=true;
yy[i][j]=numy;
}
if (s[i][j]=='#')
line=false;
}
}
if (numx==0||numy==0)
{
cout<<0<<endl;
return;
}
for (int i=0;i<nn;i++)
for (int j=0;j<mm;j++)
{
if (s[i][j]=='o')
{
assert(xx[i][j]>=1);
assert(yy[i][j]>=1);
mat[xx[i][j]-1][yy[i][j]-1]=1;
}
}
assert(numx<=MAXN);
assert(numy<=MAXN);
n=numx;m=numy;
cout<<hungary()<<endl;
}
int main()
{
int T,cas=1;
cin>>T;
while (T--)
{
printf("Case :%d\n",cas++);
Gao();
}
return 0;
}