HDU 4687 Boke and Tsukkomi (一般图最大匹配)带花树
Posted 00isok
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 4687 Boke and Tsukkomi (一般图最大匹配)带花树相关的知识,希望对你有一定的参考价值。
<题目链接>
题目大意:
给你n个点和m条边,每条边代表两点具有匹配关系,问你有多少对匹配是冗余的。
解题分析:
所谓不冗余,自然就是这对匹配关系处于最大匹配中,即该匹配关系有意义。那怎样判断该匹配是否在最大匹配中呢?我们可以枚举每一对匹配,然后对其进行取消其匹配关系,对其余的匹配跑一遍最大匹配,如果是原始最大匹配-1,说明这对匹配关系在最大匹配关系中。需要注意的是,删除匹配关系的时候,不经要将该边的匹配关系删除,还需将所有点与这两点之间的匹配关系删除(即相当于删除这两点)。
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #include <cmath> 5 #include <algorithm> 6 #include <queue> 7 #include <vector> 8 using namespace std; 9 #define MAXN 310 10 #define CLR(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 { 19 bool inpath[MAXN]={false}; 20 while(1) 21 { 22 u=base[u]; 23 inpath[u]=true; 24 if(match[u]==-1)break; 25 u=pre[match[u]]; 26 } 27 while(1) 28 { 29 v=base[v]; 30 if(inpath[v])return v; 31 v=pre[match[v]]; 32 } 33 } 34 35 //压缩花 36 void reset(int u,int anc) 37 { 38 while(u!=anc) 39 { 40 int v=match[u]; 41 inblossom[base[u]]=1; 42 inblossom[base[v]]=1; 43 v=pre[v]; 44 if(base[v]!=anc)pre[v]=match[u]; 45 u=v; 46 } 47 } 48 49 void contract(int u,int v,int n) 50 { 51 int anc=findancestor(u,v); 52 CLR(inblossom,0); 53 reset(u,anc);reset(v,anc); 54 if(base[u]!=anc)pre[u]=v; 55 if(base[v]!=anc)pre[v]=u; 56 for(int i=1;i<=n;i++) 57 if(inblossom[base[i]]) 58 { 59 base[i]=anc; 60 if(!inque[i]) 61 { 62 Q.push_back(i); 63 inque[i]=1; 64 } 65 } 66 } 67 68 bool dfs(int S,int n) 69 { 70 for(int i=0;i<=n;i++)pre[i]=-1,inque[i]=0,base[i]=i; 71 Q.clear();Q.push_back(S);inque[S]=1; 72 while(!Q.empty()) 73 { 74 int u=Q.front();Q.pop_front(); 75 for(int v=1;v<=n;v++) 76 { 77 if(g[u][v]&&base[v]!=base[u]&&match[u]!=v) 78 { 79 if(v==S||(match[v]!=-1&&pre[match[v]]!=-1))contract(u,v,n); 80 else if(pre[v]==-1) 81 { 82 pre[v]=u; 83 if(match[v]!=-1)Q.push_back(match[v]),inque[match[v]]=1; 84 else 85 { 86 u=v; 87 while(u!=-1) 88 { 89 v=pre[u]; 90 int w=match[v]; 91 match[u]=v; 92 match[v]=u; 93 u=w; 94 } 95 return true; 96 } 97 } 98 } 99 } 100 } 101 return false; 102 } 103 104 int solve(int n) 105 { 106 CLR(match,-1); 107 int ans=0; 108 for(int i=1;i<=n;i++) 109 if(match[i]==-1&&dfs(i,n)) 110 ans++; 111 return ans; 112 } 113 /*-- 以上为带花树求一般图最大匹配的模板 --*/ 114 bool vis[200]; 115 int a[200],b[200]; 116 int main() { 117 int n , m; 118 while(scanf("%d%d",&n,&m) != EOF) { 119 CLR(g,false);CLR(vis,false); 120 for(int i = 1; i <= m; i++) { 121 scanf("%d%d",&a[i],&b[i]); 122 g[a[i]][b[i]] = g[b[i]][a[i]] = true; 123 } 124 int ans = solve(n); 125 vector<int> vec; 126 for(int i = 1; i <= m; i++) { //枚举不进行匹配边 127 int x = a[i] , y = b[i]; 128 CLR(g,false); //清空匹配关系,接下来进行重置 129 for(int j = 1; j <= m; j++) if(i!=j){ 130 int tmp1 = a[j] , tmp2 = b[j]; 131 if(tmp1==x||tmp1==y||tmp2==x||tmp2==y)continue; //为什么是将所有包含这两点之间匹配关系的全部(即删除点)清除 ??? 132 g[tmp1][tmp2] = g[tmp2][tmp1] = true; 133 } 134 int tmp = solve(n); 135 if(tmp != ans - 1) { //如果删除这条边后,最大匹配数不是原始值-1,说明这条边不在最大匹配中 136 vec.push_back(i); 137 } 138 } 139 printf("%d ",vec.size()); 140 if(vec.size()>0) { 141 printf("%d",vec[0]); 142 for(int i = 1; i < vec.size(); i++) { 143 printf(" %d",vec[i]); 144 } 145 } 146 puts(""); 147 } 148 return 0; 149 }
2018-11-19
以上是关于HDU 4687 Boke and Tsukkomi (一般图最大匹配)带花树的主要内容,如果未能解决你的问题,请参考以下文章