1. 程式人生 > >HDU 4687 Boke and Tsukkomi (一般圖最大匹配)【帶花樹】

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\n",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