1. 程式人生 > >LuoguP2764 最小路徑覆蓋問題(最大流)

LuoguP2764 最小路徑覆蓋問題(最大流)

 

題目描述

«問題描述:

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

每條邊的容量均為1。求網路G1的( 0 x , 0 y )最大流。

«程式設計任務:

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

輸入輸出格式

輸入格式:

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

輸出格式:

從第1 行開始,每行輸出一條路徑。檔案的最後一行是最少路徑數。

解題思路:

轉換一下思路,需要覆蓋,那麼最多就需要點數條路徑。

然後發現,有些路徑可以合併,而且每合併一個點集,就少一條路徑。

那麼什麼樣的點可以合併呢,就是一條邊相連的。

那麼將一個點分裂成兩個一個用於接受合併,一個用來提供合併。

相連的點,從起點的提供指向終點的接受,流量為$inf$

每個點都可以是起點終點所以向源匯點連$1$的邊。

最大流最後拿n減掉就好了。

程式碼:

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 const int oo=0x3f3f3f3f;
  5 namespace stb{
  6     template<class tnt>
  7     class queue{
  8         public:
  9             queue(){h=1,t=0;}
 10             int nxt(int x){if(x+1==1000000)return
1;return x+1;} 11 void push(tnt x){t=nxt(t);l[t]=x;return ;} 12 bool empty(void){return nxt(t)==h;} 13 tnt front(void){return l[h];} 14 void clear(void){h=1,t=0;} 15 void pop(void){h=nxt(h);} 16 private: 17 tnt l[1000000]; 18 int h,t; 19 }; 20 }; 21 struct pnt{ 22 int hd; 23 int now; 24 int lyr; 25 int nxt; 26 bool nos; 27 }p[1000]; 28 struct ent{ 29 int twd; 30 int lst; 31 int vls; 32 }e[100000]; 33 int cnt; 34 int n,m; 35 int s,t; 36 stb::queue<int>Q; 37 void ade(int f,int t,int v) 38 { 39 cnt++; 40 e[cnt].twd=t; 41 e[cnt].vls=v; 42 e[cnt].lst=p[f].hd; 43 p[f].hd=cnt; 44 return ; 45 } 46 bool Bfs(void) 47 { 48 Q.clear(); 49 for(int i=1;i<=n*2+2;i++) 50 p[i].lyr=0; 51 p[s].lyr=1; 52 Q.push(s); 53 while(!Q.empty()) 54 { 55 int x=Q.front(); 56 Q.pop(); 57 for(int i=p[x].hd;i;i=e[i].lst) 58 { 59 int to=e[i].twd; 60 if(p[to].lyr==0&&e[i].vls>0) 61 { 62 p[to].lyr=p[x].lyr+1; 63 if(to==t) 64 return true; 65 Q.push(to); 66 } 67 } 68 } 69 return false; 70 } 71 int Dfs(int x,int fll) 72 { 73 if(x==t) 74 return fll; 75 for(int &i=p[x].now;i;i=e[i].lst) 76 { 77 int to=e[i].twd; 78 if(p[to].lyr==p[x].lyr+1&&e[i].vls>0) 79 { 80 int ans=Dfs(to,std::min(fll,e[i].vls)); 81 if(ans>0) 82 { 83 e[i].vls-=ans; 84 e[((i-1)^1)+1].vls+=ans; 85 p[x].nxt=to; 86 if(x!=s) 87 p[to-n].nos=true; 88 return ans; 89 } 90 } 91 } 92 return 0; 93 } 94 void Dinic(void) 95 { 96 int ans=0; 97 while(Bfs()) 98 { 99 for(int i=1;i<=2*n+2;i++) 100 p[i].now=p[i].hd; 101 int dlt; 102 while(dlt=Dfs(s,oo)) 103 ans+=dlt; 104 } 105 for(int i=1;i<=n;i++) 106 { 107 if(!p[i].nos) 108 { 109 for(int j=i;j!=t-n&&j>0;j=p[j].nxt-n) 110 printf("%d ",j); 111 puts(""); 112 } 113 } 114 printf("%d\n",n-ans); 115 return ; 116 } 117 int main() 118 { 119 scanf("%d%d",&n,&m); 120 s=n*2+1,t=n*2+2; 121 for(int i=1;i<=n;i++) 122 { 123 ade(s,i,1); 124 ade(i,s,0); 125 ade(i+n,t,1); 126 ade(t,n+i,0); 127 } 128 for(int i=1;i<=m;i++) 129 { 130 int a,b; 131 scanf("%d%d",&a,&b); 132 ade(a,b+n,oo); 133 ade(b+n,a,0); 134 } 135 Dinic(); 136 return 0; 137 }