【UOJ 79】 一般图最大匹配 (✿带花树开花)
从前一个和谐的班级,所有人都是搞OI的。有 n 个是男生,有 0 个是女生。男生编号分别为 1,…,n。
现在老师想把他们分成若干个两人小组写动态仙人掌,一个人负责搬砖另一个人负责吐槽。每个人至多属于一个小组。
有若干个这样的条件:第 v 个男生和第 u 个男生愿意组成小组。
请问这个班级里最多产生多少个小组?
输入格式
第一行两个正整数,n,m。保证 n≥2。
接下来 m 行,每行两个整数 v,u 表示第 v 个男生和第 u 个男生愿意组成小组。保证 1≤v,u≤n,保证 v≠u,保证同一个条件不会出现两次。
输出格式
第一行一个整数,表示最多产生多少个小组。
接下来一行 n 个整数,描述一组最优方案。第 v 个整数表示 v 号男生所在小组的另一个男生的编号。如果 v 号男生没有小组请输出 0。
样例一
input
10 20 9 2 7 6 10 8 3 9 1 10 7 1 10 9 8 6 8 2 8 1 3 1 7 5 4 7 5 9 7 8 10 4 9 1 4 8 6 3 2 5output
5 9 5 6 10 2 3 8 7 1 4样例二
input
5 4 1 5 4 2 2 1 4 3output
2 2 1 4 3 0限制与约定
1≤n≤500,1≤m≤124750
时间限制:1s
空间限制:256MB
【分析】
推荐博客:http://blog.csdn.net/yihuikang/article/details/10460997
http://blog.csdn.net/jackyguo1992/article/details/11271497
上模板:
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #include<queue> using namespace std; #define Maxn 510 #define Maxm 1247501+100 int n; struct node { int x,y,next; }t[Maxm*2]; int first[Maxn],len; void ins(int x,int y) { t[++len].x=x;t[len].y=y; t[len].next=first[x];first[x]=len; } int fa[Maxn],nt[Maxn],mark[Maxn],match[Maxn]; int vis[Maxn],nw; int ffa(int x) { if(fa[x]!=x) fa[x]=ffa(fa[x]); return fa[x]; } int merge(int x,int y) { fa[ffa(x)]=ffa(y); } queue<int > q; //找环 int LCA(int x,int y) { nw++; while(1) { if(x) { x=ffa(x); if(vis[x]==nw) return x; vis[x]=nw; if(match[x]) x=nt[match[x]]; else x=0; } int tt=x;x=y;y=tt; } } //奇环缩点 void shrink(int x,int rt) { while(x!=rt) { int y=match[x],z=nt[y]; if(ffa(z)!=rt) nt[z]=y; if(mark[y]==2) {q.push(y);mark[y]=1;} if(mark[z]==2) {q.push(z);mark[z]=1;} merge(x,y);merge(y,z); x=z; } } void augment(int now) { nw=0; for(int i=1;i<=n;i++) nt[i]=0,vis[i]=0,mark[i]=0,fa[i]=i; while(!q.empty()) q.pop(); q.push(now);mark[now]=1; while(!q.empty()) { int x=q.front();q.pop(); if(match[now]) return;//当前搜索节点找到增广路 for(int i=first[x];i;i=t[i].next) { int y=t[i].y; if(match[x]==y||ffa(x)==ffa(y)) continue; if(mark[y]==2) continue; //奇环缩点 if(mark[y]==1) { int rt=LCA(x,y); if(ffa(x)!=rt) nt[x]=y; if(ffa(y)!=rt) nt[y]=x; shrink(x,rt);shrink(y,rt); } //增广 else if(!match[y]) { nt[y]=x; for(int j=y;j;) { int k=nt[j],z=match[k]; match[j]=k;match[k]=j; j=z; } break; } //之前匹配过 else { nt[y]=x; q.push(match[y]); mark[match[y]]=1; mark[y]=2; } } } } int main() { int m; scanf("%d%d",&n,&m); len=0; memset(first,0,sizeof(first)); for(int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); ins(x,y);ins(y,x); } int ans=0; memset(match,0,sizeof(match)); for(int i=1;i<=n;i++) if(!match[i]) augment(i); for(int i=1;i<=n;i++) if(match[i]) ans++; ans/=2; printf("%d\n",ans); for(int i=1;i<=n;i++) printf("%d ",match[i]); printf("\n"); return 0; }
✿我认为所谓带花树的树,指匈牙利树,奇环缩点构成花✿
2017-03-04 11:26:08