HDU4687 Boke and Tsukkomi
题目链接:https://vjudge.net/problem/HDU-4687
知识点: 带花树开花算法
解题思路:
先求出原来的一般图的最大匹配数\(iCnt\). 然后枚举每一个组合,尝试去掉图中所有以这个组合中任意一点为端点的边,求出此时的最大匹配数\(tCnt\),如果\(tCnt<iCnt-1\),则这个组合对于任意一种最大匹配来说都是多余的。
AC代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef pair<int,int> P ; 4 const int maxn = 40+5, maxm = 150; 5 int N,M; 6 bool Graph[maxn][maxn],G[maxn][maxn]; 7 int Match[maxn]; 8 bool InQueue[maxn],InPath[maxn],InBlossom[maxn]; 9 int Head,Tail; 10 int Queue[maxn]; 11 int Start,Finish; 12 int NewBase; 13 int Father[maxn],Base[maxn]; 14 15 P inp[maxm]; 16 17 void Push(int u){ 18 Queue[Tail]=u; 19 Tail++; 20 InQueue[u]=true; 21 } 22 int Pop(){ 23 int res=Queue[Head]; 24 Head++; 25 return res; 26 } 27 int FindCommonAncestor(int u,int v){ 28 memset(InPath,false,sizeof(InPath)); 29 while(1){ 30 u=Base[u]; 31 InPath[u]=true; 32 if(u==Start) break; 33 u=Father[Match[u]]; 34 } 35 while(1){ 36 v=Base[v]; 37 if(InPath[v]) break; 38 v=Father[Match[v]]; 39 } 40 return v; 41 } 42 void ResetTrace(int u){ 43 int v; 44 while(Base[u]!=NewBase){ 45 v=Match[u]; 46 InBlossom[Base[u]]=InBlossom[Base[v]]=true; 47 u=Father[v]; 48 if(Base[u]!=NewBase) Father[u]=v; 49 } 50 } 51 void BloosomContract(int u,int v){ 52 NewBase = FindCommonAncestor(u,v); 53 memset(InBlossom,false,sizeof(InBlossom)); 54 ResetTrace(u); ResetTrace(v); 55 if(Base[u]!=NewBase) Father[u]=v; 56 if(Base[v]!=NewBase) Father[v]=u; 57 for(int tu=1;tu<=N;tu++){ 58 if(InBlossom[Base[tu]]){ 59 Base[tu]=NewBase; 60 if(!InQueue[tu]) Push(tu); 61 } 62 } 63 } 64 void FindAugmentingPath(){ 65 memset(InQueue,false,sizeof(InQueue)); 66 memset(Father,0,sizeof(Father)); 67 for(int i=1;i<=N;i++) Base[i]=i; 68 Head=Tail=1; 69 Push(Start); 70 Finish=0; 71 while(Head<Tail){ 72 int u=Pop(); 73 for(int v=1;v<=N;v++){ 74 if(Graph[u][v]&&(Base[u]!=Base[v])&&(Match[u]!=v)){ 75 if((v==Start)||(Match[v]>0)&&(Father[Match[v]]>0)) 76 BloosomContract(u,v); 77 else if(Father[v]==0){ 78 Father[v]=u; 79 if(Match[v]>0) Push(Match[v]); 80 else{ 81 Finish=v; 82 return; 83 } 84 } 85 } 86 } 87 } 88 } 89 void AugumentPath(){ 90 int u,v,w; 91 u=Finish; 92 while(u>0){ 93 v=Father[u]; 94 w=Match[v]; 95 Match[v]=u; 96 Match[u]=v; 97 u=w; 98 } 99 } 100 void Edmonds(){ 101 memset(Match,0,sizeof(Match)); 102 for(int u=1;u<=N;u++){ 103 if(Match[u]==0){ 104 Start =u; 105 FindAugmentingPath(); 106 if(Finish>0) AugumentPath(); 107 } 108 } 109 } 110 111 int main(){ 112 int u,v; 113 while(scanf("%d%d",&N,&M)==2){ 114 memset(G,false,sizeof(G)); 115 memset(Graph,false,sizeof(Graph)); 116 for(int i=1;i<=M;i++){ 117 scanf("%d%d",&u,&v); 118 inp[i]=make_pair(u,v); 119 Graph[u][v]=Graph[v][u]=G[u][v]=G[v][u]=true; 120 } 121 Edmonds(); 122 int iCount=0; 123 for(int u=1;u<=N;u++){ 124 if(Match[u]>0) iCount++; 125 }iCount/=2; 126 vector<int> ans; 127 for(int i=1;i<=M;i++){ 128 int u=inp[i].first,v=inp[i].second; 129 for(int j=1;j<=N;j++) Graph[u][j]=Graph[j][u]=Graph[v][j]=Graph[j][v]=false; 130 Edmonds(); 131 int tCount=0; 132 for(int u=1;u<=N;u++){ 133 if(Match[u]>0) tCount++; 134 }tCount/=2; 135 if(tCount<iCount-1) ans.push_back(i); 136 for(int j=1;j<=N;j++){ 137 Graph[u][j]=G[u][j]; 138 Graph[j][u]=G[j][u]; 139 Graph[v][j]=G[v][j]; 140 Graph[j][v]=G[j][v]; 141 } 142 } 143 int sz=ans.size(); 144 printf("%d\n",sz); 145 for(int i=0;i<sz;i++){ 146 if(i!=0) printf(" "); 147 printf("%d",ans[i]); 148 } 149 printf("\n"); 150 } 151 return 0; 152 }
“这些年我一直提醒自己一件事情,千万不要自己感动自己。大部分人看似的努力,不过是愚蠢导致的。什么熬夜看书到天亮,连续几天只睡几小时,多久没放假了,如果这些东西也值得夸耀,那么富士康流水线上任何一个人都比你努力多了。人难免天生有自怜的情绪,唯有时刻保持清醒,才能看清真正的价值在哪里。”