您的位置:首页 > 其它

poj 2226 二分图 最小顶点覆盖 “草泥马”

2012-03-03 20:57 302 查看
参考地址:http://hi.baidu.com/%BA%A3%CF%E0%C1%AC/blog/item/33dc572f55a1bf4b4fc226a7.html

题意:图中的"*"代表泥泞,"."代表草,要把所以泥泞的地方全铺上板,板可以进行叠加,输出最小的板数。

一开始看着这道题目,有点儿摸不着头脑,果然像平哥跟龙哥说的那样,这道题的建图模式十分神奇。

画图画了好久才领略到大牛们的风范。

例如:

**...

*.***

.****

.....

建图的时候先从行开始。相连的那些坑坑洼洼标上相同的数字(有图有真相)

行:(用数组rr[][]来标识)

11000

20333

04444

00000

列:(用数组cc[][]来标识)

12000

10456

03456

00000

这就是分开的行列图。不过这里离用匈牙利算法的最小覆盖来解决还差一小步。

mat[][]数组就是用来标识二分图两边节点的东东。现在转换成mat[rr[i][j]][cc[i][j]]~~这里我之前一直都理解得不是很好,但是画了个图之后,一切都真相大白了。

画出的图是这样的:




这种行列的构图方式将所有的草地都排除掉了,把坑都连起来的所有可能均建成一个新的图,如上。。太奇妙了……

#include<iostream>
using namespace std;
int r[2500][2500],c[2500][2500];
bool g[2500][2500];
bool vis[2500];
int link[2500];
char S[55][55];
int nx,ny;
bool dfs(int u)
{
for(int i=1;i<=ny;i++)
{
if(!vis[i]&&g[u][i])
{
vis[i]=1;
if(link[i]==-1||dfs(link[i]))
{
link[i]=u;
return true;
}
}
}
return false;
}
int maxmatch()
{
int num=0;
memset(link,-1,sizeof(link));
for(int i=1;i<=nx;i++)
{
memset(vis,0,sizeof(vis));
if(dfs(i))  num++;
}
return num;
}
int main()
{
int R,C;
int  flag;
while(scanf("%d%d",&R,&C)!=EOF)
{
memset(r,0,sizeof(r));
memset(c,0,sizeof(c));
for(int i=0;i<R;i++)
cin>>S[i];
nx=0;
for(int i=0;i<R;i++)
for(int j=0;j<C;j++)
{
if(S[i][j]=='*')
{
nx++;
for(int k=j;S[i][k]=='*';k++)
{
r[i][k]=nx;
j=k;
}
}
}
ny=0;
for(int j=0;j<C;j++)
for(int i=0;i<R;i++)
{
if(S[i][j]=='*')
{
ny++;
for(int k=i;S[k][j]=='*';k++)
{
c[k][j]=ny;
i=k;
}
}
}
for(int i=0;i<R;i++)
for(int j=0;j<C;j++)
g[r[i][j]][c[i][j]]=1;
/*for(int i=0;i<R;i++)
{
for(int j=0;j<C;j++)
printf("%d ",c[i][j]);
printf("\n");
} */
printf("%d\n",maxmatch());//经典构图啊,“草泥马”
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: