题:http://uoj.ac/problem/79
没什么好说的,只是区别于二分图
算法:带花树算法
#includeusing namespace std; #define fo(i,a,b) for(int i=a;i<=b;i++) #define fod(i,a,b) for(int i=b;i>=a;i--) const int N=550; int n,head[N],pre[N],match[N],f[N],col[N],cmp[N],tot; const int M=5e5+5; struct node{ int u,v,nextt; }e[M]; int num; void addedge(int u,int v){ e[num].v=v; e[num].nextt=head[u]; head[u]=num++; } int find(int x){ return f[x]==x?x:f[x]=find(f[x]); } int lca(int x,int y){//整个lca实现比较巧妙,由于是BFS,那么这两个点在当前奇环上的深度一定相等,交替暴力寻找lca即可。 tot++; x=find(x),y=find(y); while(cmp[x]!=tot){ cmp[x]=tot; x=find(pre[match[x]]); if(y) swap(x,y); } return x; } queue<int>que; void make(int x,int y,int w){//缩环(开花)过程 while(find(x)!=w){ pre[x]=y,y=match[x];//x是原本的黑点,y是原本的白点,将原本的pre边变成双向。 if(col[y]==2)//若y还是白点则染黑 col[y]=1,que.push(y); if(find(x)==x) f[x]=w; if(find(y)==y) f[y]=w; x=pre[y]; } } int solve(int st){ while(!que.empty()) que.pop(); que.push(st); fo(i,1,n) f[i]=i,pre[i]=col[i]=0; col[st]=1;//1 is black while(!que.empty()){ int u=que.front(); que.pop(); for(int i=head[u];~i;i=e[i].nextt){ int v=e[i].v; if(find(v)==find(u)||col[v]==2) continue;//如果找到一个已经缩过的奇环或者偶环则跳过 if(!col[v]){ col[v]=2,pre[v]=u; if(!match[v]){//找到增广路 for(int x=v,y;x;x=y){//返回修改匹配 y=match[pre[x]]; match[x]=pre[x]; match[pre[x]]=x; } return 1; } //否则将其匹配点加入队列 col[match[v]]=1; que.push(match[v]); } else{ int LCA=lca(u,v); make(u,v,LCA); make(v,u,LCA);//以上分别修改到lca的路径以及v到lca的路径(环的两半) } } } return 0; } int main(){ int m; memset(head,-1,sizeof(head)); scanf("%d%d",&n,&m); fo(i,1,m){ int u,v; scanf("%d%d",&u,&v); addedge(u,v); addedge(v,u); } int ans=0; fo(i,1,n) if(!match[i]) ans+=solve(i); printf("%d\n",ans); fo(i,1,n) printf("%d ",match[i]); return 0; }