1. 程式人生 > >HDU - 1083 Courses(二分圖匹配)

HDU - 1083 Courses(二分圖匹配)

include namespace 模板 string sta struct while sizeof make

二分圖匹配的模板

二分圖:如果頂點集 V可分割為兩個互不相交的子集X和Y,並且圖中每條邊連接的兩個頂點一個在 X中,另一個在 Y中,則稱圖G為二分圖。

交替路:從一個未匹配點出發,依次經過非匹配邊、匹配邊、非匹配邊…形成的路徑叫交替路

增廣路:兩個端點都是未蓋點的交替路叫做可增廣路。

偽代碼:

bool(u)

{

  for(u所連的點)

  {

    if v不在交替路上

    {

      將v加入交替路

      if v點未匹配||有可能有增長路

      {

        標記;

        ture;

      }

    }

  }

  false;

}

 1 #include<algorithm>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<stack>
 6 #include<queue>
 7 #include<cmath>
 8 #include<set>
 9 
10 
11 #define ll long long
12 #define mem(a,b) memset(a,b,sizeof(a))
13
#define inf 0x3f3f3f3f 14 15 using namespace std; 16 17 const int maxn=3e4+10; 18 19 struct edge{ 20 int u,v,next; 21 }e[maxn*2]; 22 23 int g[maxn*2],vis[maxn*2],dis[maxn*2],cheek[maxn]; 24 int tot; 25 26 void init() 27 { 28 mem(g,0); 29 mem(vis,0); 30 mem(e,0); 31 mem(dis,0
); 32 tot=0; 33 } 34 35 void make_edge(int u,int v) 36 { 37 e[++tot]=(edge){u,v,g[u]}; 38 g[u]=tot; 39 } 40 41 bool dfs(int u) 42 { 43 for(int i=g[u];i>0;i=e[i].next) 44 { 45 int v=e[i].v; 46 if(!cheek[v])//如果v不在交替路上 47 { 48 cheek[v]=1;//將v加入交替路 49 if(!vis[v]||dfs(vis[v]))//如果v點未被覆||有可能有增廣路 標記 50 { 51 //vis[u]=v; 52 vis[v]=u; 53 return true;//如果有增廣路 54 } 55 } 56 } 57 return false;// 58 } 59 60 int hungarian(int n,int m) 61 { 62 int ans=0; 63 for(int u=m+1;u<=n+m;u++)//枚舉一個集合的點 64 { 65 if(vis[u]==0)//未被覆蓋 66 { 67 mem(cheek,0); 68 if(dfs(u)) ans++;//匹配++; 69 } 70 } 71 return ans; 72 } 73 74 int main(){ 75 int t; 76 scanf("%d",&t); 77 while(t--) 78 { 79 init(); 80 int n,m; 81 scanf("%d%d",&n,&m); 82 for(int i=1;i<=n;i++) 83 { 84 int t; 85 scanf("%d",&t); 86 for(int j=1;j<=t;j++) 87 { 88 int now; 89 scanf("%d",&now); 90 make_edge(m+i,now); 91 //make_edge(now,m+i); 92 } 93 } 94 int temp=hungarian(n,m); 95 //cout<<temp<<endl; 96 cout<<(temp==n?"YES":"NO")<<endl; 97 } 98 return 0; 99 }

HDU - 1083 Courses(二分圖匹配)