poj 2226 Muddy Fields

/*

题意: 有R×C方阵,'*'表示洼地,需要铺上宽度为1的木板,长度不限,
木板只能横放或竖放.木板可以重叠,但不能覆盖'.'(草地)
求覆盖所有'*'的最少木板数.

思路:将所有横向且连续(一个或以上)的'*'看成一个点并对其进行编号,所有的编号都为集合X内的编号。
同样地,将所有的竖向且连续(一个或以上)的'*'看成一个点并对其编号,所有的编号都为集合Y内的编号
对于原图里的'*',设其在横向X编号为i,在竖向Y编号为j,则在点 Xi 和点 Yj 间连一条边,
这样构成一个二分图,问题就变成最小点覆盖数

*/

#include<iostream> //求二分图的最小点覆盖数
#include<cstring>
using namespace std;
int n1,n2; //n1,n2分别是子集X,Y的大小
int X[60][60],Y[60][60]; //X[i][j]表示ch[i][j]在横向X的编号
int edge[3000][3000],vis[3000],link[3000];
void init()
{
int r,c;
char ch[60][60];
cin>>r>>c;
for(int i=1;i<=r;++i) // 下标范围[1,1]-[r,c]
{
cin>>ch[i]+1;
}
int s,t;
n1=0;
for(int i=1;i<=r;++i) //在水平方向上查找连续的'*'
{
s=1;
do
{
while(s<=c&&ch[i][s]=='.') //连续'*'的起点s
s++;
t=s;
while(t+1<=c&&ch[i][t+1]=='*') //连续'*'的终点t
t++;
if(t<=c)
{
++n1;
for(int j=s;j<=t;++j) //离散化,将横向且连续(一个或以上)的'*'看成一个点并对其进行编号
X[i][j]=n1;
s=t+1;
}
else
break;
}while(1);
}

n2=0;
for(int j=1;j<=c;++j) //在垂直方向上查找连续的'*'
{
s=1;
do
{
while(s<=r&&ch[s][j]=='.') //连续'*'的起点s
s++;
t=s;
while(t+1<=r&&ch[t+1][j]=='*') //连续'*'的终点t
t++;
if(t<=r)
{
++n2;
for(int i=s;i<=t;++i) //离散化,将竖向且连续(一个或以上)的'*'看成一个点并对其进行编号
Y[i][j]=n2;
s=t+1;
}
else
break;
}while(1);
}

memset(edge,0,sizeof(edge));
memset(link,0,sizeof(link));
for(int i=1;i<=r;++i)
{
for(int j=1;j<=c;++j)
{
if(ch[i][j]=='*')
{
edge[X[i][j]][Y[i][j]]=1; //如果是'*'则在X,Y对应的编号之间连一条边
}
}
}
}
int find(int a)
{
for(int i=1;i<=n2;++i)
{
if(edge[a][i]&&!vis[i])
{
vis[i]=1;
if(link[i]==0||find(link[i]))
{
link[i]=a;
return 1;
}
}
}
return 0;
}
int main()
{
init();
int ans=0;
for(int i=1;i<=n1;++i)
{
memset(vis,0,sizeof(vis));
if(find(i))
{
ans++;
}
}
cout<<ans<<endl;
return 0;
}

posted on 2011-07-22 22:49  sysu_mjc  阅读(179)  评论(0编辑  收藏  举报

导航