LuoguP2764 最小路徑覆蓋問題(最大流)
阿新 • • 發佈:2019-01-01
題目描述
«問題描述:
給定有向圖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 }