剛一看到這道題十分的懵,完全不知道從何下手
然後看了看題解後發現,這道題的關鍵就是計算可以合併多少次路徑,然後最小的路徑覆蓋數就是總點數-合併次數。
舉個例子:(僅僅是讓你理解上面一句話,而不一定是真正的**執行流程)
初始:
合併1次:
合併2次:
合併3次:
所以最後最小路徑覆蓋數即為:5-3=2
(注意:1、4號點之間不能合併,因為路徑是鏈狀的,這說明了很重要的一點:每乙個點都最多只能合併其它點一次,被合併一次,這正是之後在建網路時要把源點到x的邊和x'到匯點的邊的容量賦值為1的原因)
通過思考再看一看題解,我們發現:
可以先把每個點拆開,其中乙個代表由這個點為起點(x),另乙個代表由這個點為終點(x')。
然後在源點(s)與每乙個x之間連一條容量為1的邊,在每乙個x'與匯點(t)之間連一條容量為1的邊。
最後對於每乙個輸入的邊(x,y),我們都在x與y'之間連一條容量為inf的邊。
tips:一定不要忘加反向邊!一定不要忘加反向邊!一定不要忘加反向邊!(因為介個我調了好久qaq)
那麼如果有一條路徑s-x-y'-t的流量為1,那就說明將x所代表的點與y'所代表的點合併。
所以在我們跑完一遍最大流之後,得到的最大流量就是合併次數。
最小的路徑覆蓋數(答案)就是總點數-合併次數。
#include#include#include#define maxn 1010
#define maxm 100010
#define inf 0x3f3f3f3f
using namespace std;
int bg[maxn],nt[maxm],to[maxm],w[maxm],e=1;
int q[maxn<<2],dep[maxn],n,m,s,t,ans,nxt[maxn],pre[maxn];
void insert(int x,int y,int z)
int bfs()
}return dep[t];
}int dfs(int x,int s)
}return res;
}int dinic()
return res;
}int main()
for (i=1;i<=m;i++)
ans=n-dinic();
for (i=2;i<=e;i+=2)
if (n對了,講一下我的方案輸出方法:(利用雙向鍊錶維護)
在跑玩dinic後掃一下每一條(正向)邊(構造的網路邊),如果這條邊連線著兩個非源非匯的點(x,y)且它的反向邊不為0(即這條邊被流過),就使pre[y]=x; nxt[x]=y;
最後輸出時就看當前點的前驅是否為0,若是,其就為一條路徑的起始點,從它開始一直遍歷其後繼並輸出,直到跑完為止
tips:一定要注意細節,比如x'在變回原來的點時要-n
完結散花qwq
洛谷P2764 最小路徑覆蓋
給定有向圖 g v,e 設 p 是 g 的乙個簡單路 頂點不相交 的集合。如果 v 中每個定點恰好在p的一條路上,則稱 p 是 g 的乙個路徑覆蓋。p中路徑可以從 v 的任何乙個定點開始,長度也是任意的,特別地,可以為 0 g 的最小路徑覆蓋是 g 所含路徑條數最少的路徑覆蓋。設計乙個有效演算法求乙...
P2764 最小路徑覆蓋問題
我做24題的第六題,輸出路徑還是有點糊塗 給定有向圖g v,e 設p是圖g上若干點不相交的簡單路徑的集合,若每個點v屬於v都存在於唯一一條p中的路徑上,則p是g的一條路徑覆蓋。路徑數量最少的路徑覆蓋稱為最小路徑覆蓋。用minpc g 表示圖g的最小路徑覆蓋數.有向無環圖的最小路徑覆蓋問題可轉化為二分...
P2764 最小路徑覆蓋問題
問題描述 每條邊的容量均為1。求網路g1的 0 x 0 y 最大流。程式設計任務 對於給定的給定有向無環圖g,程式設計找出g的乙個最小路徑覆蓋。輸入格式 件第1 行有2個正整數n和m。n是給定有向無環圖g 的頂點數,m是g 的邊數。接下來的m行,每行有2 個正整數i和j,表示一條有向邊 i,j 輸出...