标签:
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 8434 | Accepted: 3124 |
Description
Input
Output
Sample Input
4 4 *.*. .*** ***. ..*.
Sample Output
4
题意:“*”代表沼泽,“。”表示草坪。牛要回家,不能踩草坪,所以只能走沼泽,遇到有沼泽的地方就要主人铺板子,问最少铺多少板子。
思路:典型的二分图匹配中的最小点覆盖。但是不得不说这个建图简直太神奇了!反正我是想不出来,orz。
建图方式按照先行后列。
把行里面连在一起的坑连起来视为一个点,即一块横木板,编上序号
1 0 2 0
0 3 3 3
4 4 4 0
0 0 5 0
再按列做一次则为:
1 0 4 0
0 3 4 5
2 3 4 0
0 0 4 0
一个坑只能被横着的或者被竖着的木板盖住,将原图的坑的也标上不同的序号,一共九个坑
1 . 2 .
. 3 4 5
67 8 .
. . 9 .
比如7号坑可以被横着的4号木板和竖着的3号木板盖住,把每个点的对应的横木板(4)和竖木板(3)中间连一条边的话,则问题转化为 找尽量少的边把这些点都盖住
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <iostream> #include <algorithm> #include <queue> #include <set> using namespace std; int n,m; int cnt1,cnt2; int G[1010][1010]; int vis[1010]; int link[1010]; char map[110][110]; int m1[110][110]; int m2[110][110]; int dfs(int u) { int i; for(i=0; i<cnt2; i++) { if(G[u][i]&&!vis[i]) { vis[i]=1; if(link[i]==-1|| dfs(link[i])) { link[i] = u; return 1; } } } return 0; } void build_tu() { int i,j; cnt1=cnt2=0; for(i=0; i<n; i++) for(j=0; j< m; j++) { if(map[i][j]=='*') { while(map[i][j]=='*') { m1[i][j]=cnt1; j++; } cnt1++; } } for(i=0; i<m; i++) for(j=0; j<n; j++) { if(map[j][i]=='*') { while(map[j][i]=='*') { m2[j][i]=cnt2; j++; } cnt2++; } } /*for(i=1;i<=n;i++) for(j=1;j<=m;j++) { if(j==m) printf("%d\n",m1[i][j]); else printf("%d ",m1[i][j]); } for(i=1;i<=n;i++) for(j=1;j<=m;j++) { if(j==m) printf("%d\n",m2[i][j]); else printf("%d ",m2[i][j]); }*/ for(i=0; i<n; i++) for(j=0; j<m; j++) { if(map[i][j]=='*') G[m1[i][j]][m2[i][j]]=1; } } int main() { int i; int sum; while(~scanf("%d %d",&n,&m)) { sum=0; memset(G, 0, sizeof(G)); memset(m1, 0, sizeof(m1)); memset(m2, 0, sizeof(m2)); memset(link,-1,sizeof(link)); for(i=0; i<n; i++) scanf("%s", map[i]); build_tu(); for(i=0; i<cnt1; i++) { memset(vis,0,sizeof(vis)); if(dfs(i)) { //printf("%d---->",dfs(i)); sum++; } } printf("%d\n", sum); } return 0; }
POJ 2226-Muddy Fields(二分图_最小点覆盖+神建图orz)
标签:
原文地址:http://blog.csdn.net/u013486414/article/details/42712041