POJ 2594 Treasure Exploration(最小路径覆盖)

来源:互联网 发布:it狂人女主角 编辑:程序博客网 时间:2024/06/09 20:58

题意:给出n个点m条有向边,现在要用若干条路径覆盖所有点,每条路径不可以有重点但是不同路径之间可以有重点,问最少要用多少条这样的路径。

思路:最小路径覆盖问题的变种,经典的最小路径覆盖问题中要求不同路径之间不可以有相同的点,而这道题可以。

其实这样只需要在原图上新建几条边就可以转化为一般的路径覆盖问题,将原图中任意两个可达点之间建立一条新边(Floyd算法),这样做的依据是使得可以不经过重复的点但是还可以到达本来能到的点,这样一来就可以在新图上求出二分图的最大匹配,然后用点的总数减去匹配数就是最后的答案了。

#include<cstdio>#include<cstring>#include<cmath>#include<cstdlib>#include<iostream>#include<algorithm>#include<vector>#include<map>#include<queue>#include<stack>#include<string>#include<map>#include<set>#include<ctime>#define eps 1e-6#define LL long long#define pii pair<int, int>//#pragma comment(linker, "/STACK:1024000000,1024000000")using namespace std;const int MAXN = 510;//const int INF = 0x3f3f3f3f;int n, m;int linker[MAXN];bool used[MAXN];int G[MAXN][MAXN];int uN, vN;bool dfs(int u){for (int v = 1; v <= vN; v++){if(G[u][v] && !used[v]){used[v] = 1;if(linker[v]==-1 || dfs(linker[v])) {linker[v] = u;return true;}}}return false;}int hungary(){int res = 0;memset(linker, -1, sizeof(linker));int u;for (u = 1; u <= uN; u++){        memset(used, 0, sizeof(used));        if(dfs(u)) res++;}return res;}void floyd(){    for(int k = 1; k <= n; k++)        for(int i = 1; i <= n; i++)            for(int j = 1; j <= n; j++)                G[i][j] |= G[i][k] & G[k][j];}int main(){    //freopen("input.txt", "r", stdin);while(cin>>n>>m && n)    {        memset(G, 0, sizeof(G));        uN = vN = n;        for(int i = 1; i <= m; i++)        {            int u, v;            scanf("%d%d", &u, &v);            G[u][v] = 1;        }        floyd();        int ans = n - hungary();        cout << ans << endl;}    return 0;}


0 0
原创粉丝点击