poj 2226 Muddy Fields
/*
题意 :有R×C方阵,'*'表示洼地,需要铺上宽度为1的木板,长度不限,只能横放或竖放.木板可以重叠,但不能覆盖'.'
求覆盖所有'*'洼地所用的最少木板数.
构图: 将所有横向且连续(一个或以上)的'*'看成一个点并对其进行编号,所有的编号都为集合X内的编号。同样地,将所有的竖向且连续(一个或以上)的'*'看成一个点并对其编号,所有的编号都为集合Y内的编号
对于原图里的'*',设其在横向X编号为i,在竖向Y编号为j,则在点 Xi 和点 Yj 间连一条边,
这样构成一个二分图,问题就变成一个最小点覆盖问题,于是转化成二分图的最大匹配
*/
![ContractedBlock.gif](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<iostream> //求二分图的最小覆盖点集
#include<cstring>
using namespace std;
char ch[60][60];
int r,c,row[60][60],colo[60][60];
int edge[3000][3000],vis[3000],result[3000],x,y;
bool find(int a)
{
for(int i=1;i<=y;++i)
if(edge[a][i]==1&&vis[i]==0)
{
vis[i]=1;
if(result[i]==0||find(result[i]))
{
result[i]=a;
return true;
}
}
return false;
}
int main()
{
cin>>r>>c;
memset(edge,0,sizeof(edge));
memset(result,0,sizeof(result));
for(int i=1;i<=r;++i)
{
cin>>ch[i]+1;
}
int s,t;
x=0;
for(int i=1;i<=r;++i) //在水平方向上查找连续的'*'
{
s=1;
do
{
while(s<=c&&ch[i][s]=='.')
s++;
t=s;
while(t+1<=c&&ch[i][t+1]=='*')
t++;
if(t<=c)
{
++x;
for(int j=s;j<=t;++j)
row[i][j]=x;
s=t+1;
}
}while(t<=c);
}
y=0;
for(int j=1;j<=c;++j) //在垂直方向上查找连续的'*'
{
s=1;
do
{
while(s<=r&&ch[s][j]=='.')
s++;
t=s;
while(t+1<=r&&ch[t+1][j]=='*')
t++;
if(t<=r)
{
++y;
for(int i=s;i<=t;++i)
colo[i][j]=y;
s=t+1;
}
}while(t<=r);
}
for(int i=1;i<=r;++i)
for(int j=1;j<=c;++j)
{
if(ch[i][j]=='*')
edge[row[i][j]][colo[i][j]]=1; //如果是'*'则在相应的集合X,Y编号内连一条边
}
int ans=0;
for(int i=1;i<=x;++i)
{
memset(vis,0,sizeof(vis));
if(find(i))
{
ans++;
}
}
cout<<ans<<endl;
return 0;
}