洛谷OJ:P2764 最小路徑覆蓋問題(網路流)
題目描述
給定有向圖 G=(V,E) 。設 P 是 G 的一個簡單路(頂點不相交)的集合。如果 V 中每個定點恰好在P的一條路上,則稱 P 是 G 的一個路徑覆蓋。P中路徑可以從 V 的任何一個定點開始,長度也是任意的,特別地,可以為 0 。G 的最小路徑覆蓋是 G 所含路徑條數最少的路徑覆蓋。設計一個有效演算法求一個 DAG (有向無環圖) G 的最小路徑覆蓋。
提示:設 V={1,2,...,n} ,構造網路 G1={V1,E1} 如下:
V1={x0,x1,...,xn}∪{y0,y1,...,yn}
E1={(x0,xi):i∈V}∪{(yi,y0):i∈V}∪{(xi,yj):(i,j)∈E}
每條邊的容量均為 1 ,求網路 G1 的 (x0,y0) 最大流。
輸入格式
第一行有 2 個正整數 n 和 m 。 nn 是給定GAP(有向無環圖) G 的頂點數, m 是 G 的邊數。接下來的 m行,每行有兩個正整數 i 和 j 表示一條有向邊 (i,j)。
輸出格式
從第1 行開始,每行輸出一條路徑。檔案的最後一行是最少路徑數。
輸入輸出樣例
輸入 #1複製
11 12
1 2
1 3
1 4
2 5
3 6
4 7
5 8
6 9
7 10
8 11
9 11
10 11
輸出 #1複製
1 4 7 10 11
2 5 8
3 6 9
3
說明/提示
1≤n≤150,1≤m≤6000
由@FlierKing提供SPJ
思路:利用網路流解決最少路徑覆蓋的問題一般建圖方式是將每個點拆分成兩個點【例如點的標號為x,則我們可以拆分成x和x+】,分別與源點和匯點相連,如下圖所示【出處:巨巨的知乎】:
建圖前:
建圖後:
在該圖中,我們令每一條從源點指向匯點的邊的邊長為1,跑一遍最大流,便能得到最大合併路徑數,再用點數去減即得最小路徑覆蓋數。這幾乎是顯然的:從A點到B'點的每一條流,都代表著一次合併。而從源點只給每個點輸送1單位流量,又保證了每個點只被經過一次。【同樣摘自上述連結】,對於本題輸出路徑的操作,只需額外開一個nxt陣列即可,而起點x一定是edges[x+n][t]=1的點。【t是匯點】。
#include<set>
#include<map>
#include<queue>
#include<vector>
#include<string>
#include<math.h>
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<functional>
using namespace std;
#define maxn 550
#define ll long long
#define inf 1e18
int n,m,s,t,lv[maxn],cur[maxn],nxt[maxn];
ll edges[maxn][maxn];
//lv是每個點的層數
bool bfs(){
memset(lv,-1,sizeof(lv));
lv[s]=0;
queue<int>q;
q.push(s);
while(!q.empty()){
int now=q.front();
q.pop();
for(int i=1;i<=2*n+1;i++){
if(edges[now][i]>0 && lv[i]==-1){
lv[i]=lv[now]+1;
q.push(i);
}
}
}
return lv[t]!=-1;
}
ll dfs(int p=s,ll flow=inf){
if(p==t)
return flow;
ll mn=flow;
for(int i=1;i<=2*n+1;i++){
if(edges[p][i]>0 && lv[i]==lv[p]+1){
ll c=dfs(i,min(edges[p][i],mn));
mn-=c;
edges[p][i]-=c;
edges[i][p]+=c;
if(c && p) nxt[p]=i-n;
}
}
return flow-mn;
}
ll dinic(){
ll maxFlow=0;
while(bfs())
maxFlow+=dfs();
return maxFlow;
}
int main(void){
int x,y;
scanf("%d%d",&n,&m);
t=2*n+1;
for(int i=1;i<=n;i++){
edges[s][i]=1;
edges[i+n][t]=1;
}
for(int i=1;i<=m;i++){
scanf("%d%d",&x,&y);
edges[x][y+n]=1;
}
ll pathNum=n-dinic();
for(int i=1;i<=n;i++){
if(edges[i+n][t]){
int now=i;
printf("%d",now);
while(nxt[now]){
now=nxt[now];
printf(" %d",now);
}
printf("\n");
}
}
printf("%lld\n",pathNum);
return 0;
}
相關文章
- 最小路徑可重複點覆蓋
- [HAOI2007][洛谷P2218]覆蓋問題
- 最大匹配、最小頂點覆蓋、最大獨立集、最小路徑覆蓋(轉)(再轉)
- 洛谷 P11011 點的覆蓋
- poj2594Treasure Exploration【最小路徑覆蓋+floyd傳遞閉包】
- 洛谷八皇后問題
- HDU 4606 Occupy Cities (計算幾何+最短路+最小路徑覆蓋)
- 【洛谷OJ】【JAVA】P1036 選數Java
- 線段覆蓋問題
- LeetCode 64號問題 最小路徑和LeetCode
- 四、建立覆蓋網路--Flannel
- firefox覆蓋原來網頁的問題Firefox網頁
- 病毒全球”勒索”歐亞企業網路安全保險覆蓋問題突出
- 【洛谷OJ】【JAVA】P1149 火柴棒等式Java
- 洛谷P1644跳馬問題
- 【離散優化】覆蓋問題優化
- 演算法題:頂點覆蓋問題演算法
- 辦公室無線覆蓋方案解決網路死角難題
- 網洛流
- 洛谷網校學習
- 動態規劃6:臺階問題和矩陣最小路徑問題動態規劃矩陣
- 學校無線網路覆蓋方案
- 洛谷P2404 自然數的拆分問題——題解
- 洛谷
- 洛谷P7368 [USACO05NOV] Asteroids G 題解 二分圖最小點覆蓋 匈牙利演算法AST演算法
- 演算法題系列:頂點覆蓋問題演算法
- 被網際網路覆蓋的真實世界
- 洛谷題單指南-字串-Test字串
- 洛谷-P9574 題解
- 洛谷 p1605 迷宮問題 詳解
- 網際網路公司無線覆蓋解決方案
- Google S2 是如何解決空間覆蓋最優解問題的?Go
- 洛谷-P9830 題解
- 洛谷P5057簡單題
- 分治演算法-求解棋盤覆蓋問題演算法
- 樹上最小點覆蓋的一類問題
- WIFI網路覆蓋的定義是什麼WiFi
- ITU:行動網路全球覆蓋率達90%