POJ 2594 Treasure Exploration(Floyd+最小路径覆盖)
题意:求有向图的最小路径覆盖,但是点可以被多条路径重复走过!
求最小路径覆盖的问题:HDU1151, 链接: http://acm.hdu.edu.cn/showproblem.php?pid=1151
分析:点能被重复覆盖是和单纯地求最小路径覆盖的区别,这样的话在一个弱连通子图中,可能出现中间结点已经被走过,但是之后的点没被覆盖的情况,这时匹配的结果就会比原来大。
那么可以通过求出图的传递闭包来加边,将原来没有直接边的点建立关系,这样就能得到正确结果。
#include<iostream> #include<stdio.h> #include<cmath> #include<cstring> #include<algorithm> #define Lson rt<<1,l,m #define Rson rt<<1|1,m+1,r using namespace std; typedef long long LL; const int maxn = 1e3+5,maxm = 2e5+5; int N; struct Edge{ int to,next; }edges[maxm]; int head[maxn],tot; int linker[maxn]; bool used[maxn]; void init() { tot=0; memset(head,-1,sizeof(head)); } void AddEdge(int u,int v) { edges[tot].to = v; edges[tot].next = head[u]; head[u] = tot++; } bool dfs(int u){ int v,st,ed; for(int i=head[u];~i;i = edges[i].next){ v = edges[i].to; if(!used[v]){ used[v]=true; if(linker[v]==-1||dfs(linker[v])){ linker[v]=u; return true; } } } return false; } int hungary(){ int res=0; memset(linker,-1,sizeof(linker)); for(int u=1;u<=N;u++){ memset(used,0,sizeof(used)); if(dfs(u)) res++; } return res; } void Floyd() { for(int u=1;u<=N;++u){ for(int i = head[u];~i;i =edges[i].next){ int v=edges[i].to; for(int j=head[v];~j;j=edges[j].next){ AddEdge(u,edges[j].to); } } } } void debug() { } int main() { #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); freopen("out.txt","w",stdout); #endif int T,M,u,v,tmp,k; while(scanf("%d%d",&N,&M)==2){ if(!N) break; init(); for(int i=1;i<=M;++i){ scanf("%d%d",&u,&v); AddEdge(u,v); } Floyd(); printf("%d\n",N-hungary()); } return 0; }
为了更好的明天