#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
int n,m;//地图大小
char map[100][100];//地图
int x[3030],y[3030];//x表示与xi匹配的y顶点,y表示与yi匹配的x顶点
int xs[300][300],ys[300][300]; //水平方向上的块编号 垂直方向上的块编号
int xn,yn1;//水平方向上的块个数 垂直方向上的块个数
bool g[3030][3030];
int t[3030];
bool path(int u)
{
int v;
for(v=1;v<=yn1;v++)//考虑所有yi顶点
{
if(g[u][v]&&!t[v])//v跟u邻接并且v没有访问过
{
t[v]=1;
//如果v没有匹配 或v已经匹配了,但是从y[v]出发可以找到一条增广路
if(!y[v]||path(y[v]))
{
x[u]=v;y[v]=u;
return 1;
}
}
}
return 0;//如果不存在从u出发的增广路
}
void maxmatch()//求二部图的最大匹配算法
{
int i,ans=0;//最大匹配数
memset(x,0,sizeof x);
memset(y,0,sizeof y);//从0匹配开始增广
for(i=1;i<=xn;i++)
{
if(!x[i])//从每个未盖点出发找增广路
{
memset(t,0,sizeof t);
if(path(i))//每找到一条增广路,可使得匹配数加1
ans++;
}
}
printf("%d\n",ans);
}
int main()
{
int k,kase;
int i,j;
int number;//用来对水平方向和垂直方向上的块进行编号的序号
int flag;//一个块开始的标志
scanf("%d",&kase);
for(k=0;k<kase;k++)
{
printf("Case :%d\n",k+1);
scanf("%d%d",&m,&n);//读入地图大小
memset(xs,0,sizeof xs);
memset(ys,0,sizeof ys);
for(i=0;i<m;++i)//读入地图
scanf("%s",map[i]);
number=0;//用来对时评方向和垂直方向上的块进项编号的序号
for(i=0;i<m;++i)//对时评方向上的块进行编号
{
flag=0;
for(j=0;j<n;j++)
{
if(map[i][j]=='o')
{
if(flag==0)number++;
xs[i][j]=number,flag=1;
}
else if(map[i][j]=='#')flag=0;
}
}
xn=number,number=0;
for(j=0;j<n;j++)//地垂直方向上的块进行编号
{
flag=0;
for(i=0;i<m;++i)
{
if(map[i][j]=='o')
{
if(flag==0)number++;
ys[i][j]=number,flag=1;
}
else if(map[i][j]=='#')flag=0;
}
}
yn1=number;
memset(g,0,sizeof g);
for(i=0;i<m;i++)
{
for(j=0;j<n;j++)
{
//对水平方向和垂直方向上的块进行连接 若两个块有公共的空地 则在它们之间连边
if(xs[i][j])g[xs[i][j]][ys[i][j]]=1;
}
}
maxmatch();
}
return 0;
}
二分图最大匹配(匈牙利算法)
最新推荐文章于 2024-01-13 23:43:09 发布