URAL 1099 Work Scheduling (一般图最大匹配) 模板题【带花树】

<题目链接>

<转载于 >>>  >

题目大意:
 给出n个士兵,再给出多组士兵之间两两可以匹配的关系。已知某个士兵最多只能与一个士兵匹配。求最多能够有多少对匹配,并输出这些匹配。

解题分析:
本题不一定是二分图,所以求最大匹配不能用匈牙利,因为该一般图可能出现奇环。本题用带花树求解,下面是带花树的模板。

  1 #include <iostream>  
  2 #include <stdio.h>  
  3 #include <string.h>  
  4 #include <cmath>  
  5 #include <algorithm>  
  6 #include <queue>  
  7 using namespace std;  
  8 #define MAXE 250*250*2  
  9 #define MAXN 250  
 10 #define SET(a,b) memset(a,b,sizeof(a))  
 11 deque<int> Q;  
 12 //g[i][j]存放关系图:i,j是否有边,match[i]存放i所匹配的点  
 13 bool g[MAXN][MAXN],inque[MAXN],inblossom[MAXN];  
 14 int match[MAXN],pre[MAXN],base[MAXN];  
 15   
 16 //找公共祖先  
 17 int findancestor(int u,int v){  
 18     bool inpath[MAXN]={false};  
 19     while(1){  
 20         u=base[u];  
 21         inpath[u]=true;  
 22         if(match[u]==-1)break;  
 23         u=pre[match[u]];  
 24     }  
 25     while(1){  
 26         v=base[v];  
 27         if(inpath[v])return v;  
 28         v=pre[match[v]];  
 29     }  
 30 }  
 31   
 32 //压缩花  
 33 void reset(int u,int anc){  
 34     while(u!=anc){  
 35         int v=match[u];  
 36         inblossom[base[u]]=1;  
 37         inblossom[base[v]]=1;  
 38         v=pre[v];  
 39         if(base[v]!=anc)pre[v]=match[u];  
 40         u=v;  
 41     }  
 42 }  
 43   
 44 void contract(int u,int v,int n){  
 45     int anc=findancestor(u,v);  
 46     memset(inblossom,0,sizeof(inblossom));  
 47     reset(u,anc);reset(v,anc);  
 48     if(base[u]!=anc)pre[u]=v;  
 49     if(base[v]!=anc)pre[v]=u;  
 50     for(int i=1;i<=n;i++)  
 51         if(inblossom[base[i]]){  
 52             base[i]=anc;  
 53             if(!inque[i]){  
 54                 Q.push_back(i);  
 55                 inque[i]=1;  
 56             }  
 57         }  
 58 }  
 59   
 60 bool dfs(int S,int n){  
 61     for(int i=0;i<=n;i++)pre[i]=-1,inque[i]=0,base[i]=i;  
 62     Q.clear();Q.push_back(S);inque[S]=1;  
 63     while(!Q.empty()){  
 64         int u=Q.front();Q.pop_front();  
 65         for(int v=1;v<=n;v++){  
 66             if(g[u][v]&&base[v]!=base[u]&&match[u]!=v){  
 67                 if(v==S||(match[v]!=-1&&pre[match[v]]!=-1))contract(u,v,n);  
 68                 else if(pre[v]==-1){  
 69                     pre[v]=u;  
 70                     if(match[v]!=-1)Q.push_back(match[v]),inque[match[v]]=1;  
 71                     else{  
 72                         u=v;  
 73                         while(u!=-1){  
 74                             v=pre[u];  
 75                             int w=match[v];  
 76                             match[u]=v;  
 77                             match[v]=u;  
 78                             u=w;  
 79                         }  
 80                         return true;  
 81                     }  
 82                 }  
 83             }  
 84         }  
 85     }  
 86     return false;  
 87 }  
 88 int main(){  
 89     int n,m,a,b,ans;  
 90     while(scanf("%d",&n)!=EOF){  
 91         ans=0;         
 92         memset(match,-1,sizeof(match));  
 93         memset(g,0,sizeof(g));  
 94         while(scanf("%d%d",&a,&b)!=EOF&&a!=0){  
 95             g[a][b]=g[b][a]=1;  
 96         }  
 97         for(int i=1;i<=n;i++){  
 98             if(match[i]==-1&&dfs(i,n)){  
 99                 ans++;    //ans记录最多有几对匹配
100             }  
101         }  
102         cout<<ans*2<<endl;   //输出巡逻的人数
103         for(int i=1;i<=n;i++){  
104             if(match[i]!=-1){  
105                 printf("%d %d\n",i,match[i]);  
106                 match[i]=match[match[i]]=-1;  
107             }  
108         }  
109     }  
110     return 0;  
111 }  

 

 

2018-11-19

posted @ 2018-11-19 22:14  悠悠呦~  阅读(337)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end