HDU-4687 Boke and Tsukkomi 带花树,枚举
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4687
题意:给一个无向图,求所有的最大匹配的情况所不包含的边。。
数据比较小,直接枚举边。先求一次最大匹配hig,然后依次枚举所有边,假设此边为一个匹配,那么删掉边的两个节点,然后再剩下的图中求最大匹配t,如果t<hig-1那么就是不包含的边了。关于一般图上的最大匹配算法,O(n^3)的Edmonds's matching algorithm,理解起来比较容易,但是写起来比较麻烦,收集了一个模板,by Amber。。。
1 //STATUS:C++_AC_46MS_236KB 2 #include <functional> 3 #include <algorithm> 4 #include <iostream> 5 //#include <ext/rope> 6 #include <fstream> 7 #include <sstream> 8 #include <iomanip> 9 #include <numeric> 10 #include <cstring> 11 #include <cassert> 12 #include <cstdio> 13 #include <string> 14 #include <vector> 15 #include <bitset> 16 #include <queue> 17 #include <stack> 18 #include <cmath> 19 #include <ctime> 20 #include <list> 21 #include <set> 22 //#include <map> 23 using namespace std; 24 //#pragma comment(linker,"/STACK:102400000,102400000") 25 //using namespace __gnu_cxx; 26 //define 27 #define pii pair<int,int> 28 #define mem(a,b) memset(a,b,sizeof(a)) 29 #define lson l,mid,rt<<1 30 #define rson mid+1,r,rt<<1|1 31 #define PI acos(-1.0) 32 //typedef 33 typedef __int64 LL; 34 typedef unsigned __int64 ULL; 35 //const 36 const int N=42; 37 const int INF=0x3f3f3f3f; 38 const int MOD=100000,STA=8000010; 39 const LL LNF=1LL<<60; 40 const double EPS=1e-8; 41 const double OO=1e15; 42 const int dx[4]={-1,0,1,0}; 43 const int dy[4]={0,1,0,-1}; 44 const int day[13]={0,31,28,31,30,31,30,31,31,30,31,30,31}; 45 //Daily Use ... 46 inline int sign(double x){return (x>EPS)-(x<-EPS);} 47 template<class T> T gcd(T a,T b){return b?gcd(b,a%b):a;} 48 template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;} 49 template<class T> inline T lcm(T a,T b,T d){return a/d*b;} 50 template<class T> inline T Min(T a,T b){return a<b?a:b;} 51 template<class T> inline T Max(T a,T b){return a>b?a:b;} 52 template<class T> inline T Min(T a,T b,T c){return min(min(a, b),c);} 53 template<class T> inline T Max(T a,T b,T c){return max(max(a, b),c);} 54 template<class T> inline T Min(T a,T b,T c,T d){return min(min(a, b),min(c,d));} 55 template<class T> inline T Max(T a,T b,T c,T d){return max(max(a, b),max(c,d));} 56 //End 57 58 int a,b; 59 int n,m; 60 int head,tail,Start,Finish; 61 int link[N]; //表示哪个点匹配了哪个点 62 int Father[N]; //这个就是增广路的Father……但是用起来太精髓了 63 int Base[N]; //该点属于哪朵花 64 int Q[N]; 65 bool mark[N]; 66 bool map[N][N]; 67 bool InBlossom[N]; 68 bool in_Queue[N]; 69 70 void BlossomContract(int x,int y) 71 { 72 fill(mark,mark+n+1,false); 73 fill(InBlossom,InBlossom+n+1,false); 74 #define pre Father[link[i]] 75 int lca,i; 76 for (i=x;i;i=pre) {i=Base[i]; mark[i]=true; } 77 for (i=y;i;i=pre) {i=Base[i]; if (mark[i]) {lca=i; break;} } //寻找lca之旅……一定要注意i=Base[i] 78 for (i=x;Base[i]!=lca;i=pre){ 79 if (Base[pre]!=lca) Father[pre]=link[i]; //对于BFS树中的父边是匹配边的点,Father向后跳 80 InBlossom[Base[i]]=true; 81 InBlossom[Base[link[i]]]=true; 82 } 83 for (i=y;Base[i]!=lca;i=pre){ 84 if (Base[pre]!=lca) Father[pre]=link[i]; //同理 85 InBlossom[Base[i]]=true; 86 InBlossom[Base[link[i]]]=true; 87 } 88 #undef pre 89 if (Base[x]!=lca) Father[x]=y; //注意不能从lca这个奇环的关键点跳回来 90 if (Base[y]!=lca) Father[y]=x; 91 for (i=1;i<=n;i++){ 92 if(i==a || i==b)continue; 93 if (InBlossom[Base[i]]){ 94 Base[i]=lca; 95 if (!in_Queue[i]){ 96 Q[++tail]=i; 97 in_Queue[i]=true; //要注意如果本来连向BFS树中父结点的边是非匹配边的点,可能是没有入队的 98 } 99 } 100 } 101 } 102 103 void Change() 104 { 105 int x,y,z; 106 z=Finish; 107 while (z){ 108 y=Father[z]; 109 x=link[y]; 110 link[y]=z; 111 link[z]=y; 112 z=x; 113 } 114 } 115 116 void FindAugmentPath() 117 { 118 fill(Father,Father+n+1,0); 119 fill(in_Queue,in_Queue+n+1,false); 120 for (int i=1;i<=n;i++) Base[i]=i; //Init属于同一花朵 121 head=0; tail=1; 122 Q[1]=Start; //当前节点进入队列 123 in_Queue[Start]=1; 124 while (head!=tail){ 125 int x=Q[++head]; 126 for (int y=1;y<=n;y++){ 127 if(y==a || y==b)continue; 128 if (map[x][y] && Base[x]!=Base[y] && link[x]!=y){ //无意义的边 129 if ( Start==y || link[y] && Father[link[y]] ) //精髓地用Father表示该点是否 130 BlossomContract(x,y); 131 else if (!Father[y]){ 132 Father[y]=x; 133 if (link[y]){ 134 Q[++tail]=link[y]; 135 in_Queue[link[y]]=true; 136 } 137 else{ 138 Finish=y; 139 Change(); 140 return; 141 } 142 } 143 } 144 } 145 } 146 } 147 148 int Edmonds() 149 { 150 int i,cnt=0; 151 memset(link,0,sizeof(link)); 152 memset(Father,0,sizeof(Father)); 153 for (Start=1;Start<=n;Start++){ 154 if(Start==a || Start==b)continue; 155 if (link[Start]==0) 156 FindAugmentPath(); //如果点没有匹配,那么找BFS增广路 157 } 158 159 for(i=1;i<=n;i++) 160 if(link[i])cnt++; 161 return cnt; 162 } 163 164 int e[130][2],ans[130]; 165 166 int main(){ 167 // freopen("in.txt","r",stdin); 168 int i,j,hig,cnt; 169 while(~scanf("%d%d",&n,&m)) 170 { 171 mem(map,0); 172 for(i=0;i<m;i++){ 173 scanf("%d%d",&e[i][0],&e[i][1]); 174 map[e[i][0]][e[i][1]]=map[e[i][1]][e[i][0]]=true; 175 } 176 177 a=b=-1; 178 hig=Edmonds(); 179 cnt=0; 180 for(i=0;i<m;i++){ 181 a=e[i][0],b=e[i][1]; 182 int t=Edmonds(); 183 if(t<hig-2)ans[cnt++]=i+1; 184 } 185 186 printf("%d\n",cnt); 187 if(cnt){ 188 printf("%d",ans[0]); 189 for(i=1;i<cnt;i++) 190 printf(" %d",ans[i]); 191 } 192 putchar('\n'); 193 } 194 return 0; 195 }