这道题又是理解了老半天。。。才看懂,我们把行联通块列联通块放在左右两侧,有交点就连边。然后求一下最小覆盖,这个含义是什么呢,我们知道我们知道其实最小覆盖可以理解为点来覆盖边,边覆盖完意味着什么呢,就是原来的图被完全覆盖了(最好可以画画看)反正我是想不出这么牛的建模的。。。还是太弱,,,
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#define N 55
#define M N*N
using namespace std;
int n,ny,nx,m;
int map[M][M];
int cx[M],cy[M],mark[M];
char str[N][N];
int map_x[N][N],map_y[N][N];
int path(int u)
{
int j;
for(j=1;j<=ny;j++)
{
if(map[u][j]&&!mark[j])
{
mark[j]=1;
if(cy[j]==-1||path(cy[j]))
{
cx[u] = j;
cy[j] = u;
return 1;
}
}
}
return 0;
}
int maxMatch() //求最小覆盖
{
memset(cx,-1,sizeof(cx));
memset(cy,-1,sizeof(cy));
int i;
int res = 0;
for(i=1;i<=nx;i++)
{
if(cx[i]==-1)
{
memset(mark,0,sizeof(mark));
res+=path(i);
}
}
return res;
}
void getMap()
{
memset(map,0,sizeof(map));
memset(map_x,0,sizeof(map_x));
memset(map_y,0,sizeof(map_y));
int i,j;
int flag;
nx=ny=0;
for(i=0;i<n;i++) //横向分区域
{
for(j=0;j<m;j++)
{
flag = 0;
while(j<m&&str[i][j]=='*')
{
if(!flag) ++nx;
map_x[i][j] = nx;
j++;
flag = 1;
}
}
}
for(j=0;j<m;j++) //纵向分区
{
for(i=0;i<n;i++)
{
flag = 0;
while(i<n&&str[i][j]=='*')
{
if(!flag) ++ny;
flag = 1;
map_y[i][j] = ny;
i++;
}
}
}
for(i=0;i<n;i++) //横向纵向区域连接
{
for(j=0;j<m;j++)
{
int x = map_x[i][j];
int y = map_y[i][j];
if(x&&y)
{
map[x][y] = 1; //得到二分map图,然后进行最小覆盖
}
}
}
}
int main()
{
int i;
scanf("%d%d",&n,&m);
for(i=0;i<n;i++)
{
scanf("%s",str[i]);
}
getMap();
printf("%d\n",maxMatch());
return 0;
}