1340 最小路徑覆蓋 最大匹配
阿新 • • 發佈:2018-12-15
題目
定義: 一個不含圈的有向圖G中,G的一個路徑覆蓋是一個其結點不相交的路徑集合P,圖中的每一個結點僅包含於P中的某一條路徑。路徑可以從任意結點開始和結束,且長度也為任意值,包括0。請你求任意一個不含圈的有向圖G的最小路徑覆蓋數。
提示:最小路徑覆蓋數=G的定點數-最小路徑覆蓋中的邊數
最小路徑覆蓋數=原圖G的頂點數-二分圖的最大匹配數
題解
把原圖的每個點拆成兩個點,然後從有向邊的起點向終點連線,其中起點全部放在二分圖的同一邊。
這時可以把n個點看成獨立的一個路徑,然後選擇一個匹配就是把兩個路徑連起來。可以看出同一個起點不能連出兩條匹配,因為同一條路徑方向不能改變,同理同一個終點也是這樣,符合匹配的定義。
最後答案=頂點數-最大匹配數
時間複雜度
程式碼
#include <cstdio> #include <cstring> using namespace std; int t,n,m,cnt; int ls[150],ne[20005],y[20005],link[150]; bool cover[150]; bool dfs(int k){ for (int i=ls[k];i;i=ne[i]) if (!cover[y[i]]){ int t=link[y[i]]; link[y[i]]=k; cover[y[i]]=1; if (t==0||dfs(t)) return 1; link[y[i]]=t; } return 0; } int main(){ scanf("%d",&t); for (;t;t--){ scanf("%d",&n); scanf("%d",&m); cnt=0; memset(link,0,sizeof(int)*(n+3)); memset(ls,0,sizeof(int)*(n+3)); for (int i=1;i<=m;i++){ int a,b; scanf("%d%d",&a,&b); ne[++cnt]=ls[a];ls[a]=cnt;y[cnt]=b; } int ans=n; for (int i=1;i<=n;i++){ memset(cover,0,sizeof(bool)*(n+3)); if (dfs(i)) ans--; } printf("%d\n",ans); } }