| Time Limit: 6000MS | Memory Limit: 65536K | |
| Total Submissions: 7343 | Accepted: 3002 |
Description
Input
Output
Sample Input
1 0 2 1 1 2 2 0 0 0
Sample Output
1 1 2
题意:
派机器人去火星寻宝,给出一个无环的有向图,机器人可以降落在任何一个点上,再沿着路去其他点探索,我们的任务是计算至少派多少机器人就可以访问到所有的点。有的点可以重复去。
解析:这题粗略一看,有点最小路径覆盖的意思,但是和标准的最小路径覆盖问题不同在于,标准的最小路径覆盖问题是每个点只能走一次,本题的点是可以重复去走了。
但是我们可以转化一下,传递闭包建立新图,转化为标准的路径覆盖。最小路径覆盖 = 图的顶点数 – 最大匹配数。
#include <cstdio>
#include <cstring>
#include <algorithm>
#define maxn 550
using namespace std;
int map[maxn][maxn];
int used[maxn];
int link[maxn];
int n, m;
void init(){
memset(map, 0, sizeof(map));
}
void getmap(){
while(m--){
int a, b;
scanf("%d%d", &a, &b);
map[a][b] = 1;
}
}
void floyd(){
for(int k = 1; k <= n; ++k)
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= n; ++j)
map[i][j] = map[i][j] || map[i][k] && map[k][j];
}
bool dfs(int x){
for(int i = 1; i <= n; ++i){
if(map[x][i] && !used[i]){
used[i] = 1;
if(link[i] == -1 || dfs(link[i])){
link[i] = x;
return true;
}
}
}
return false;
}
int hungary(){
int ans = 0;
memset(link, -1, sizeof(link));
for(int i = 1; i <= n; ++i){
memset(used, 0, sizeof(used));
if(dfs(i))
ans++;
}
return ans;
}
int main (){
while(scanf("%d%d", &n, &m), n || m ){
init();
getmap();
floyd();
int sum = hungary();
printf("%d\n", n - sum);
}
return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
POJ 2594--Treasure Exploration【二分图 && 最小路径覆盖 && 点可以重复走 && 传递闭包】
原文地址:http://blog.csdn.net/hpuhjh/article/details/47999433