1. 程式人生 > >洛谷2764 最小路徑覆蓋問題

洛谷2764 最小路徑覆蓋問題

gpo oid form 長度 每一個 inpu dfs set 空格

問題描述:

給定有向圖G=(V,E)。設P 是G 的一個簡單路(頂點不相交)的集合。如果V 中每個頂點恰好在P 的一條路上,則稱P是G 的一個路徑覆蓋。P 中路徑可以從V 的任何一個頂點開始,長度也是任意的,特別地,可以為0。G 的最小路徑覆蓋是G 的所含路徑條數最少的路徑覆蓋。設計一個有效算法求一個有向無環圖G 的最小路徑覆蓋。

編程任務:

對於給定的給定有向無環圖G,編程找出G的一個最小路徑覆蓋。

Input Format

文件第1 行有2個正整數n和m。n是給定有向無環圖G 的頂點數,m是G 的邊數。接下來的m行,每行有2 個正整數i和j,表示一條有向邊(i,j)。

Output Format

從第1 行開始,每行輸出一條路徑(行末無空格)。文件的最後一行是最少路徑數。

網絡流經典題,網絡流24題之一

題意就是在一個有向無環圖裏,用最少的路徑數覆蓋每一個點。

就是如果i,j有一條邊,就將i和j+n連一條邊,跑一下最大匹配

最少路徑條數ans=n-最大匹配數

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 10005
#define inf 0x7fffff
int
n,m; int ans; int cnt=1; int to[maxn],head[maxn],q[maxn],h[maxn]; bool mark[maxn]; struct edge{ int next,to,w; }e[2000005]; void ins(int u,int v,int w){ cnt++; e[cnt].next=head[u];e[cnt].to=v;e[cnt].w=w; head[u]=cnt; } void insert(int u,int v,int w){ ins(u,v,w);ins(v,u,
0); } bool bfs(){ int t=0,w=1; int now; memset(h,-1,sizeof h); q[0]=h[0]=0; while(t<w){ now=q[t];t++; for(int i=head[now];i;i=e[i].next){ int s=e[i].to; if(e[i].w&&h[s]==-1){ h[s]=h[now]+1; q[w++]=s; } } } if(h[8001]==-1)return 0; return 1; } int dfs(int x,int f){ if(x==8001)return f; int w,used=0; for(int i=head[x];i;i=e[i].next){ int s=e[i].to; if(e[i].w&&h[s]==h[x]+1){ w=f-used; w=dfs(s,min(w,e[i].w)); if(w){ to[x]=s; if(s-n>0)mark[s-n]=1; } e[i].w-=w; e[i^1].w+=w; used+=w; if(used==f)return f; } } if(!used)h[x]=-1; return used; } void dinic(){ while(bfs())ans-=dfs(0,inf); } int main(){ scanf("%d%d",&n,&m); int x,y; for(int i=1;i<=m;i++){ scanf("%d%d",&x,&y); insert(x,n+y,inf); } for(int i=1;i<=n;i++)insert(0,i,1); for(int i=1;i<=n;i++)insert(i+n,8001,1); ans=n; dinic(); for(int i=1;i<=n;i++){ if(mark[i])continue; int k=i; printf("%d ",i); while(to[k]){ printf("%d ",to[k]-n); k=to[k]-n; } printf("\n"); } printf("%d",ans); }

洛谷2764 最小路徑覆蓋問題