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
作者:is_ok
出处:http://www.cnblogs.com/00isok/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。