有向無環圖最小路徑覆蓋,可以轉化成二分圖最大匹配問題,從而用最大流解決。
構造二分圖,把原圖每個頂點i拆分成二分圖x,y集合中的兩個頂點xi和yi。對於原圖中存在的每條邊(i,j),在二分圖中連線邊(xi,yj)。然後把二分圖最大匹配模型轉化為網路流模型,求網路最大流。
最小路徑覆蓋的條數,就是原圖頂點數,減去二分圖最大匹配數。沿著匹配邊查詢,就是乙個路徑上的點,輸出所有路徑即可。
對於乙個路徑覆蓋,有如下性質:
1、每個頂點屬於且只屬於乙個路徑。
2、路徑上除終點外,從每個頂點出發只有一條邊指向路徑上的另一頂點。
所以我們可以把每個頂點理解成兩個頂點,乙個是出發,乙個是目標,建立二分圖模型。該二分圖的任何乙個匹配方案,都對應了乙個路徑覆蓋方案。如果匹配數為0,那麼顯然路徑數=頂點數。每增加一條匹配邊,那麼路徑覆蓋數就減少乙個,所以路徑數=頂點數 - 匹配數。要想使路徑數最少,則應最大化匹配數,所以要求二分圖的最大匹配。
注意,此建模方法求最小路徑覆蓋僅適用於有向無環圖,如果有環或是無向圖,那麼有可能求出的一些環覆蓋,而不是路徑覆蓋。
#include using namespace std;
const int maxn = 1000;
const int maxm = 50000;
const int inf = 0x3f3f3f3f;
struct edge1
;struct dinic
edges.clear();
} void addedge(int from,int to,int cap)
); edges.push_back((edge1));
m = edges.size();
g[from].push_back(m - 2);
g[to].push_back(m - 1);
} bool bfs()
}} return vis[t];
} int dfs(int x,int a)
}return flow;
} int maxflow(int s,int t)
return flow;
}}din;
int to[500];
bool vis[500];
int main(void)
for(int i = 1; i <= n; i++) din.addedge(i + n,t,1);
int ans = n - din.maxflow(s,t);
memset(to,0,sizeof(to));
memset(vis,false,sizeof(vis));
for(int i = 0; i < din.edges.size(); i++)
}for(int i = 1; i <= n; i++)
printf("\n");}}
printf("%d\n",ans);
return 0;}/*
11 12
1 21 3
1 42 5
3 64 7
5 86 9
7 10
8 11
9 11
10 11
*/
網路流24題 最小路徑覆蓋 (最小路徑覆蓋)
題目 給定有向圖g v,e 設p是g的乙個簡單路 頂點不相交 的集合。如果v中每個頂點恰好在p的一條路上,則稱p是g的乙個路徑覆蓋。p中路徑可以從v的任何乙個頂點開始,長度也是任意的,特別地,可以為0。g的最小路徑覆蓋是g的所含路徑條數最少的路徑覆蓋。設計乙個有效演算法求乙個有向無環圖g的最小路徑覆...
最小路徑覆蓋問題(網路流24題)
問題描述 給定有向圖g v,e 設p 是g 的乙個簡單路 頂點不相交 的集合。如果v 中每個頂點恰好在p 的一條路上,則稱p是g 的乙個路徑覆蓋。p 中路徑可以從v 的任何乙個頂點開始,長度也是任意的,特別地,可以為0。g 的最小路徑覆蓋是g 的所含路徑條數最少的路徑覆蓋。設計乙個有效演算法求乙個有...
網路流24題 最小路徑覆蓋問題
p2764 傳送門 基本模型 首先結論為 將每個點 v 拆成 v,v 有向邊 edge u,v 改為 edge u,v 建成二分圖 那麼 最小路徑覆蓋數 n 二分圖最大匹配數 證明 匹配 u,v 相當於連線了 u,v 連通塊個數減一,想要連通塊最少自然要最大匹配 如果要輸出方案的話增廣時記錄 u 的...