洛谷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 點的覆蓋
- 最大匹配、最小頂點覆蓋、最大獨立集、最小路徑覆蓋(轉)(再轉)
- 洛谷八皇后問題
- LeetCode 64號問題 最小路徑和LeetCode
- 【洛谷OJ】【JAVA】P1036 選數Java
- 線段覆蓋問題
- 棋盤覆蓋問題
- 【洛谷OJ】【JAVA】P1149 火柴棒等式Java
- firefox覆蓋原來網頁的問題Firefox網頁
- 九度oj-最短路徑問題
- BZOJ1927: [Sdoi2010]星際競速(最小費用最大流 最小路徑覆蓋)
- 洛谷P1644跳馬問題
- 【離散優化】覆蓋問題優化
- 洛谷P2062 分隊問題(dp)
- 洛谷——玩具謎題
- Maven配置覆蓋內嵌tomcat虛擬對映路徑MavenTomcat
- 路徑問題
- 學校無線網路覆蓋方案
- 洛谷P7368 [USACO05NOV] Asteroids G 題解 二分圖最小點覆蓋 匈牙利演算法AST演算法
- 洛谷 p1605 迷宮問題 詳解
- 網洛流
- 洛谷P2404 自然數的拆分問題——題解
- 公園無線覆蓋維護問題
- 辦公室無線覆蓋方案解決網路死角難題
- 洛谷網校學習
- 網際網路公司無線覆蓋解決方案
- 洛谷P2323 [HNOI2006] 公路修建問題
- 樹上最小點覆蓋的一類問題
- 分治演算法-求解棋盤覆蓋問題演算法
- WIFI網路覆蓋的定義是什麼WiFi
- 洛谷題型摘選(三)
- 洛谷-P9830 題解
- 洛谷-P9574 題解
- 洛谷題單指南-字串-Test字串
- 洛谷
- 遞迴路徑問題遞迴