题目链接:https://vjudge.net/problem/19334/origin
题目大意:
如图:每个车不能“碰面”(每行每列只能一个:出除非墙隔开)
问给你一个棋盘,最多能放多少个车?多样例。
输入
4
.X…
…
XX…
…
输出:
5
思路:把行与列做匹配,把每一行和每列进行编号。有墙就是新点。
#include <bits/stdc++.h>
using namespace std;
const int N=165; // 最大点数
const int INF=1<<28; // 距离初始值
int g[N][N]; //二分图
int Mx[N]; //Mx[i]表示左集合i顶点所匹配的右集合的顶点序号
int My[N]; //My[i]表示右集合i顶点所匹配的左集合的顶点序号
int dx[N];
int dy[N];
bool used[N];
int Nx,Ny,dis;
//寻找 增广路径集
bool searchP()
{
dis=INF;
int i,v,u;
std::queue<int> Q;
memset(dx,-1,sizeof(dx));
memset(dy,-1,sizeof(dy));
for(i=1;i<=Nx;i++)
{ //cx[i]表示左集合i顶点所匹配的右集合的顶点序号
if(Mx[i]==-1)
{
//将未遍历的节点 入队 并初始化次节点距离为0
Q.push(i);
dx[i]=0;
}
}
//广度搜索增广路径
while(!Q.empty())
{
u=Q.front();
Q.pop();
if(dx[u]>dis) break;
//取右侧节点
for(v=1;v<=Ny;v++)
{
//右侧节点的增广路径的距离
if(g[u][v]&&dy[v]==-1)
{
dy[v]=dx[u]+1; //v对应的距离 为u对应距离加1
if(My[v]==-1) dis=dy[v]; //如果该点未被匹配,那么增广路形成
else //如果该点匹配了,那么接着往下搜
{
dx[My[v]]=dy[v]+1;
Q.push(My[v]);
}
}
}
}
return dis!=INF;
}
//寻找路径 深度搜索
bool DFS(int u)
{
int v;
for(v=1;v<=Ny;v++)
{
//如果该点没有被遍历过 并且距离为上一节点+1
if(g[u][v]&&!used[v]&&dy[v]==dx[u]+1)
{
//对该点染色
used[v]=true;
if(My[v]!=-1&&dy[v]==dis) continue; //如果该点已经被匹配了并且为最后一个匹配点,那么这条路径不是增广路。即是说这条路的结点已经匹配
if(My[v]==-1||DFS(My[v])) //如果该点未匹配或者后面的点能腾出位置,那么这就是增广路
{
My[v]=u;
Mx[u]=v;
return true;
}
}
}
return false;
}
//得到最大匹配的数目
int Hungary()
{
int u;
int ret=0;
memset(Mx,-1,sizeof(Mx));
memset(My,-1,sizeof(My));
while(searchP()) //如果存在增广路
{
memset(used,false,sizeof(used));
for(u=1;u<=Nx;u++)
if(Mx[u]==-1&&DFS(u)) ret++;
}
return ret;
}
char a[100][100];
int X[100][100], Y[100][100];
int main()
{
int n;
while(scanf("%d",&n),n)
{
Nx=Ny=0;
for(int i=1;i<=n;i++)
{
scanf("%s",a[i]+1);
}
memset(g,0,sizeof(g));
//Ny=Nx>Ny? Nx:Ny;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(a[i][j]=='.')
{
if(j==1||a[i][j-1]=='X')
{
Nx++;
}
X[i][j]=Nx;
}
if(a[j][i]=='.')
{
if(j==1||a[j-1][i]=='X')
{
Ny++;
}
Y[j][i]=Ny;
}
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(a[i][j]=='.')
g[X[i][j]][Y[i][j]]=1;
}
}
int ans=Hungary();
printf("%d\n",ans);
}
return 0;
}