比赛的时候刚开始看这题还以为是二分图匹配,后来才发现根本不是,因为该题存在长度为奇数的圈 。 比如1->2,2->3,3->1 。 所以该题要用一般图匹配,即带花树算法 。
比赛时抄的模板有地方抄错了,上述样例出现了死循环 。 赛后补题的时候用map去重却得不到正确答案,不知为何,暂放 ,下面给出一种正确解法。
细节参见代码:
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<vector> #include<map> #include<list> #include<cmath> #include<set> #include<queue> using namespace std; const int maxn = 55; int n,m,Match[maxn],Head,Tail,Queue[maxn],Start,Finish,NewBase,Father[maxn],Base[maxn],cnt,Count; bool InQueue[maxn],InPath[maxn],InBlossom[maxn],Graph[maxn][maxn]; void Push(int u) { Queue[Tail] = u; Tail++; InQueue[u] = true; } int Pop() { int res = Queue[Head]; Head++; return res; } int FindCommonAncestor(int u,int v) { memset(InPath,false,sizeof(InPath)); while(true) { u = Base[u]; InPath[u] = true; if(u == Start) break; u = Father[Match[u]]; } while(true) { v = Base[v]; if(InPath[v])break; v = Father[Match[v]]; } return v; } void ResetTrace(int u) { int v; while(Base[u] != NewBase) { v = Match[u]; InBlossom[Base[u]] = InBlossom[Base[v]] = true; u = Father[v]; if(Base[u] != NewBase) Father[u] = v; } } void BloosomContract(int u,int v) { NewBase = FindCommonAncestor(u,v); memset(InBlossom,false,sizeof(InBlossom)); ResetTrace(u); ResetTrace(v); if(Base[u] != NewBase) Father[u] = v; if(Base[v] != NewBase) Father[v] = u; for(int tu = 1; tu <= n; tu++) if(InBlossom[Base[tu]]) { Base[tu] = NewBase; if(!InQueue[tu]) Push(tu); } } void FindAugmentingPath() { memset(InQueue,false,sizeof(InQueue)); memset(Father,0,sizeof(Father)); for(int i = 1; i <= n; i++) Base[i] = i; Head = Tail = 1; Push(Start); Finish = 0; while(Head < Tail) { int u = Pop(); for(int v = 1; v <= n; v++) if(Graph[u][v] && (Base[u] != Base[v]) && (Match[u] != v)) { if((v == Start) || ((Match[v] > 0) && Father[Match[v]] > 0)) BloosomContract(u,v); else if(Father[v] == 0) { Father[v] = u; if(Match[v] > 0) Push(Match[v]); else { Finish = v; return; } } } } } void AugmentPath() { int u,v,w; u = Finish; while(u > 0) { v = Father[u]; w = Match[v]; Match[v] = u; Match[u] = v; u = w; } } void Edmonds() { memset(Match,0,sizeof(Match)); for(int u = 1; u <= n; u++) if(Match[u] == 0) { Start = u; FindAugmentingPath(); if(Finish > 0)AugmentPath(); } } int getMatch() { Edmonds(); Count = 0; for(int u = 1; u <= n; u++) if(Match[u] > 0) Count++; return Count/2; } struct node { int a,b; node(int a=0,int b=0): a(a),b(b) {} bool operator < (const node& rhs) const { return a < rhs.a || (a == rhs.a && b < rhs.b); } bool operator == (const node& rhs)const { return a == rhs.a && b == rhs.b; } } e[155],ee[155]; map<node,int> p; void PrintMatch() { cnt = getMatch(); vector<int> ans; int g[maxn][maxn]; memcpy(g,Graph,sizeof(g)); for(int i=0;i<m;i++) { memcpy(Graph,g,sizeof(g)); int u = e[i].a, v = e[i].b; for(int j = 1; j <= n; j++) Graph[j][u] = Graph[u][j] = Graph[j][v] = Graph[v][j] = false; int cur = getMatch(); if(cur == cnt - 1) ; else ans.push_back(i+1); } int sz = ans.size(); printf("%d\n",sz); for(int i = 0;i < sz;i++) { printf("%d",ans[i]); if(i < sz-1)printf(" "); } printf("\n"); } int main() { while(~scanf("%d%d",&n,&m)) { memset(Graph,0,sizeof(Graph)); for(int i=0; i<m; i++) { scanf("%d%d",&e[i].a,&e[i].b); Graph[e[i].a][e[i].b]=Graph[e[i].b][e[i].a]=true; } Edmonds(); PrintMatch(); } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
HDU 4687 Boke and Tsukkomi(一般图匹配|带花树)
原文地址:http://blog.csdn.net/weizhuwyzc000/article/details/48009923