1. 程式人生 > >SSLOJ 1340 最小路徑覆蓋

SSLOJ 1340 最小路徑覆蓋

題目

Description

  定義: 一個不含圈的有向圖G中,G的一個路徑覆蓋是一個其結點不相交的路徑集合P,圖中的每一個結點僅包含於P中的某一條路徑。路徑可以從任意結點開始和結束,且長度也為任意值,包括0。請你求任意一個不含圈的有向圖G的最小路徑覆蓋數。 

提示:最小路徑覆蓋數=G的定點數-最小路徑覆蓋中的邊數 
最小路徑覆蓋數=原圖G的頂點數-二分圖的最大匹配數 

Input

   t 表示有t組資料;n 表示n個頂點(n<=120);m 表示有m條邊; 
   接下來m行,每行有兩個數 i,j表示一條有向邊。 

Output

最小路徑覆蓋數

Sample Input

 

2 
4
3
3 4
1 3
2 3
3
3
1 3
1 2
2 3

 

Sample Output

 

2
1

 

分析

     

   把原圖的每個點 V 拆成 V x V y 兩個點,    如果有一條有向邊 A->B ,那麼就加邊 A x >B y    。這樣就得到了一個二分圖。
   那麼 最小路徑覆蓋=原圖的結點數-新圖的最大匹配數。  

程式碼

 1 #include<iostream>
 2 #include<vector>
 3 using namespace std;
 4 int n,m,x,y;
 5 bool cover[10001];
 6 int link[10001];
 7 vector <int> f[10001];
 8 bool find(int x)  //匹配
 9 {
10     for (int i=0;i<f[x].size();i++)
11 { 12 if (!cover[f[x][i]]) 13 { 14 cover[f[x][i]]=true; 15 int q=link[f[x][i]]; 16 link[f[x][i]]=x; 17 if (q==0||find(q)) return true; 18 link[f[x][i]]=q; 19 } 20 } 21 return false; 22 } 23 int main () 24 { 25 int T; 26 cin>>T; 27 for (int k=1;k<=T;k++) 28 { 29 cin>>n>>m; 30 memset(link,0,sizeof(link)); 31 for (int i=0;i<10000;i++) //清空向量 32 f[i].clear(); 33 for (int i=1;i<=m;i++) 34 { 35 cin>>x>>y; 36 f[x].push_back(y); 37 } 38 int ans=0; 39 for (int i=1;i<=n;i++) 40 { 41 memset(cover,false,sizeof(cover)); 42 ans+=find(i); 43 } 44 cout<<n-ans<<endl; 45 } 46 }