二分图 最大匹配 之最小点覆盖

来源:互联网 发布:真正刷钻软件 编辑:程序博客网 时间:2024/05/22 03:52

题目链接:POJ2226

题目大意:给你一个图 n*m ,由‘ * ’和‘ . ’组成 ,现在你可以用一个长度任意,宽度为1的板子去覆盖所有的*,但是不能覆盖到‘ . ’,问你至少要多少块板子。


题目分析://核心思想  如何构建一个匈牙利板子 图 
/*
把 横纵块做成图中的点 即题目变成求最小的点数使得 所有的原图单点被覆盖  
那么这里把原图单点抽象出来 当做现图的边 ,那么怎么确定对应关系呢
即使每个原图的点所在的横块和纵块在现图对应的点 连起来 就成了一个边 

*/ 

#include<iostream>#include<cstring>using namespace std;//注意map保存的是/*横纵块的个数 :最坏情况是每隔一个有一块泥,所以平均每行有m/2个 总共有n*m/2个节点  */ int map[55*55][55*55];int vis[55*55],pre[55*55];int flagrow[55][55],flagcol[55][55];int n,m;char field[55][55];int cnt1,cnt2;int dfs(int x){for(int i=1;i<=cnt2;i++){if(map[x][i]&&vis[i]==0){vis[i] = 1;if(pre[i]==0||dfs(pre[i])){pre[i] = x;return 1;}}}return 0;}int main(){while(scanf("%d%d",&n,&m)!=EOF){cnt1 = cnt2 = 1;for(int i=0;i<=n;i++)field[i][0] = '.';//第一列for(int i=0;i<=m;i++)field[0][i] = '.';//第一行 for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)scanf("\n%c",&field[i][j]);//scanf一个回车符 即在缓冲池按照回车 字符的顺序读取 memset(map,0,sizeof(map));memset(pre,0,sizeof(pre));memset(flagrow,0,sizeof(flagrow));memset(flagcol,0,sizeof(flagcol));for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){if(field[i][j]=='*'){if(field[i][j-1]=='*')//左边的{flagrow[i][j] = flagrow[i][j-1] ;}else{flagrow[i][j] =cnt1;//横块点的个数  cnt1++;}if(field[i-1][j]=='*')//上边的{flagcol[i][j] = flagcol[i-1][j] ;}else{flagcol[i][j] =cnt2;//横块点的个数  cnt2++;}}} cnt1--;cnt2--;//横块点-->竖块点 for(int i=1;i<=n;i++)for(int j=1;j<=m;j++) {if(field[i][j] == '*')map[flagrow[i][j]][flagcol[i][j]] = 1;//节点之间都有边 }////for(int i=1;i<=cnt1;i++)//for(int j=1;j<=cnt1;j++)//{//printf("%d ",flagrow[i][j]);//if(j==cnt1)//printf("\n");//}//for(int i=1;i<=max(cnt1,cnt2);i++)//for(int j=1;j<=max(cnt1,cnt2);j++)//{//printf("%d ",map[i][j]);//if(j==max(cnt1,cnt2))//printf("\n");//}int ans=0;for(int i=1;i<=cnt1;i++){memset(vis,0,sizeof(vis));ans+=dfs(i);}printf("%d\n",ans); }}


阅读全文
0 0
原创粉丝点击