标签:
| 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