Time Limit:?1000MS | ? | Memory Limit:?65536K |
Total Submissions:?6334 | ? | Accepted:?3125 |
Description
Input
Output
Sample Input
2 7 9 ooo**oooo **oo*ooo* o*oo**o** ooooooooo *******oo o*o*oo*oo *******oo 10 1 * * * o * * * * * *
Sample Output
17 5
好吧。
。
做了几道简单的匈牙利算法和简单的最小覆盖。。最终遇到一道纠结的题了。。
这题目我看了小优酱的题意解析(Orz)?点击打开链接?小优酱写解题报告真的非常具体。。
从他(她)那里我学到了非常多东西。。在此十分感谢。。尽管他(她)都不知道我。。(233)
无向二分图的最小路径覆盖 = 顶点数 – 最大二分匹配数/2
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
const int M = 1000 + 5;
int dx[]= {-1,1,0,0};
int dy[]= {0,0,-1,1};
int t, m, n; //输入数据
int link[M]; //用于推断是否为饱和点。
int city[M][M]; //用于记录城市
int v1, v2; //拆分后建立的图
int sum; //城市的总数
bool MAP[M][M]; //建立后的图
bool cover[M]; //用于查看是否为覆盖点
int ans; //最大分配值
char str; //用于输入字符串
bool dfs(int x) //匈牙利算法
{
for(int y=1; y<=v2; y++)
{
if(MAP[x][y] && !cover[y])
{
cover[y]=true;
if(!link[y] || dfs( link[y] ))
{
link[y]=x;
return true;
}
}
}
return false;
}
int main()
{
scanf("%d", &t);
while( t-- )
{
memset(city, 0, sizeof(city));
memset(link, 0, sizeof(link));
memset(MAP, false, sizeof(MAP));
ans=0;
v1=0;
v2=0;
sum=0;
scanf("%d%d", &n, &m);
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)
{
cin>>str;
if(str==‘*‘)
{
city[i][j]=++sum;
}
}
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)
if(city[i][j])
for(int k=0; k<4; k++)
if(city[ i + dx[k]][j + dy[k]])
MAP[ city[i][j] ] [ city[i + dx[k]] [ j + dy[k]] ] = true;
v1=v2=sum;
for(int i=1; i<=v1; i++)
{
memset(cover, false, sizeof(cover));
if( dfs(i) )
ans++;
}
printf("%d\n", sum-ans/2); //无向二分图:最小路径覆盖数 = "拆点"前原图的顶点数 - 最大匹配数/2
}
return 0;
}
POJ 3020:Antenna Placement(无向二分图的最小路径覆盖)
原文:https://www.cnblogs.com/ldxsuanfa/p/10888638.html