您的位置:首页 > 其它

poj 2226 Muddy Fields(合理建图+二分匹配)

2014-08-17 23:09 363 查看
/*
题意:用木板盖住泥泞的地方,不能盖住草。木板任意长!可以重叠覆盖! '*'表示泥泞的地方,'.'表示草!
思路:
首先让我们回忆一下HDU 2119 Matrix这一道题,一个矩阵中只有0, 1,然后让我们通过选择一行,或者
是一列将其所在行的或者所在列的 1全部删掉,求出最少需要几步?

这道题的思路就是:将行标 和 列标值为1的建立一条边!通过匈牙利算法可以得到这个二分图的最大匹配数
最大匹配数==最小顶点覆盖数!最小顶点覆盖就是用最少的点覆盖了这个二分图的所有的边,然后去掉这些
最小覆盖中的顶点就可以去掉所有的边,也就是所有的 1都去掉了!

那么这道题该怎么办呢?其实和上面的思路差不多,只不过是不能在原图上解题!这道题每一行或者每一列
都有限制的因素,就是草地,覆盖泥泞的地方时不能覆盖草地,所以要想办法忽略草地的影响!

解决方法:连通块的思路
如果一个连通区域的左右两侧无法延伸则为行连通块儿,上下无法延伸则为列连通块儿,把行连通块儿作为X集合,列连通块儿作为Y集合,则X与Y相连得到的边就代表所要覆盖的       泥泞区域。即可用匈牙利算法求出覆盖所有泥泞区域所需要的最少连通块儿。
1,现将每一行的不连在一起的泥泞土地赋给不同的编号(从1...cntR开始),也就是如果忽略
草地的话,泥泞的地方一共有cntR个行连通块!
2,同理每一列按照每一行的操作, 共有cntC个列连通块!
这样结题思路就和上面的那一道题一样了.....

g[i][j]=='*' 那么aR[i][j]就是该点新的行标, aC[i][j]就是该点行的列标
*/
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#define M 55
#define N 1000
using namespace std;
vector<int>v
;
char g[M][M];
int vis
;
int linker
;
int aR[M][M], aC[M][M];
int n, m;

bool dfs(int u){
int len=v[u].size();
for(int i=0; i<len; ++i){
int vu=v[u][i];
if(!vis[vu]) {
vis[vu]=1;
if(!linker[vu] || dfs(linker[vu])){
linker[vu]=u;
return true;
}
}
}
return false;
}

int main(){
while(scanf("%d%d", &n, &m)!=EOF){
int cntR=1, cntC=1;
for(int i=1; i<=n; ++i)
scanf("%s", g[i]+1);
for(int i=1; i<=n; ++i)
for(int j=1; j<=m; ++j)
if(g[i][j]=='*'){
aR[i][j]=cntR;
if(j+1>m || g[i][j+1]!='*')
++cntR;
}
for(int j=1; j<=m; ++j)
for(int i=1; i<=n; ++i)
if(g[i][j]=='*'){
aC[i][j]=cntC;
if(i+1>n || g[i+1][j]!='*')
++cntC;
}
for(int i=1; i<=n; ++i)
for(int j=1; j<=m; ++j)
if(g[i][j]=='*')
v[aR[i][j]].push_back(aC[i][j]);

int ans=0;
memset(linker, 0, sizeof(linker));
for(int i=1; i<cntR; ++i){
memset(vis, 0, sizeof(vis));
if(dfs(i))  ++ans;
}
printf("%d\n", ans);
for(int i=1; i<cntR; ++i)
v[i].clear();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: