标签:二分匹配
2 4 4 *ooo o### **#* ooo* 4 4 #*** *#** **#* ooo#
3 5
链接:http://acm.hdu.edu.cn/showproblem.php?pid=5093
题意:选尽可能多*号点,要求选得点之间必须有#阻隔,否者不能在同一行或者同一列。
做法:
先要把竖向*和O相连的 都连成一起,并编号。
然后是横着的也一样。
案例编号后:
2
4 4
*ooo
o###
**#*
ooo*
这里是竖向编号,同编号为一块
1 2 4 6
1 0 0 0
1 3 0 7
1 3 5 7
这里是横向编号
1 1 1 1
2 0 0 0
3 3 0 4
5 5 5 5
3
4 4
#***
*#**
**#*
ooo#
1 2 4 6
1 0 4 6
1 3 0 6
1 3 5 7
1 1 1 1
2 0 3 3
4 4 0 5
6 6 6 5
5
然后把竖向的每一块 都看作二分图左边的每一个点,
然后把横向的每一块 都看作二分图右边的每一个点,
星号必会对应一个竖向的块 编号, 和一个横向的块编号。
把每个星号对应的 两个编号连线。
如果匹配了,就表示这两个块都被占据了,这两个块就不能再有其他星号点被连了。
所以要知道最多有多少*可以放,就只用知道最多可以有几条边可以选。也就是求最大二分匹配了。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <malloc.h>
#include <ctype.h>
#include <math.h>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
#include <stack>
#include <queue>
#include <vector>
#include <deque>
#include <set>
#include <map>
#define N 3000
int visit[N];
int mark[N];
int match[N][N];
int n,m,k;
int dfs(int x)
{
int i;
//printf("%d\n",x);
for(i=1;i<=m;i++)//对左边的节点x与右边的节点进行逐一检查
{
if(!visit[i]&&match[x][i])
{
visit[i]=1;//标记检查过的点
if(mark[i]==-1||dfs(mark[i])) //mark如果没男的,就直接给个老公,如果已经有老公,搜他老公有没有喜欢的,有的话,该女配新男;;;
{//|| 前面过了 后面不运行;;
mark[i]=x;//修改匹配关系
return 1;
}
}
}
return 0;
}
int hungary ()
{
memset(mark,-1,sizeof(mark));
int maxx=0,j;
for(j=1;j<=n;j++)//对做部分顶点逐个进行遍历
{
memset(visit,0,sizeof(visit));
if(dfs(j))
maxx++;
}
return maxx;
}
char mp[60][60];
int cdh[60][60];
int cds[60][60];
int main()//注意 mark[m]=n mark[j] = i
{
int maxx;
int nn,mm;
int t;
scanf("%d",&t);
while(t--) //k 个配
{
scanf("%d%d",&nn,&mm);
/*
for(int i=0;i<nn;i++)
{
for(int j=0;j<mm;j++)
{
if((i+j)%2==1)
mp[i][j]='#';
else
mp[i][j]='*';
}
}*/
for(int i=0;i<nn;i++)
{
scanf("%s",mp[i]);
}
int sqi=0;
for(int j=0;j<mm;j++)//左竖着
{
for(int i=0;i<nn;i++)
{
if(mp[i][j]!='#')
{
if(i==0)
cds[i][j]=++sqi;
else if(mp[i-1][j]=='#')
cds[i][j]=++sqi;
else
cds[i][j]=sqi;
}
}
}
n=sqi;
int hqi=0;
for(int i=0;i<nn;i++) //you heng 着
{
for(int j=0;j<mm;j++)
{
if(mp[i][j]!='#')
{
if(j==0)
cdh[i][j]=++hqi;
else if(mp[i][j-1]=='#')
cdh[i][j]=++hqi;
else
cdh[i][j]=hqi;
}
}
}
m=hqi;
/*
for(int i=0;i<nn;i++)//左竖着
{
for(int j=0;j<mm;j++)
{
printf("%d ",cdh[i][j]);
}
puts("");
}
*/
memset(match,0,sizeof(match));
for(int i=0;i<nn;i++)
{
for(int j=0;j<mm;j++)
{
if(mp[i][j]=='*')
{
int z=cds[i][j];
int y=cdh[i][j];
match[z][y]=1;
}
}
}
maxx=hungary();
printf ("%d\n",maxx);
/*
scanf ("%d%d%d",&n,&m,&k)!=EOF
for(i=1;i<=k;i++)
{
int a,b;
scanf ("%d%d",&a,&b);
match[a][b]=1;//标记当前匹配关系
}
max=hungary();
printf ("%d\n",max);*/
}
return 0;
}
标签:二分匹配
原文地址:http://blog.csdn.net/u013532224/article/details/45509099