标签:二分匹配
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