【Tarjan算法】【DFS】Petrozavodsk Summer Training Camp 2016 Day 9: AtCoder Japanese Problems Selection, Thursday, September 1, 2016 Problem B. Point Pairs
这份代码可以作为找割边的模板。割边分割出来的部分是无向图的 边-双连通分量。
平面上2*n+1个点,在同一横坐标上的点之间可以任意两两匹配。同一纵坐标上的点之间也可以。问你对于所有的点i,输出i被移除之后,剩余的点能否完美匹配。
把x坐标当一列点,y坐标当一列点,原本的点当做边,建出来一个二分图。
一个连通块可以完美匹配,当且仅当其中边数为偶数。必须所有连通块的边数都是偶数,整个图才可以完美匹配。
考虑移除一个点,如果它不是割边,那么仅仅会让其所在连通块大小-1。如果其是割边,那么将其所在连通块分割成了两个连通块。就很容易在dfs的过程中统计答案。
可以做 边-双连通分量 缩点。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int n,K,xs[410000],ys[410000]; int e,first[410000],next[410000],v[410000],id[410000]; void AddEdge(int U,int V,int ID){ v[e]=V; id[e]=ID; next[e]=first[U]; first[U]=e++; } bool bridge[410000]; int dep,dfn[410000]; int Tarjan(int U,int te) { int lowU=dfn[U]=++dep; for(int i=first[U];i!=-1;i=next[i]) if(!dfn[v[i]]) { int lowV=Tarjan(v[i],id[i]); lowU=min(lowU,lowV); if(lowV>dfn[U]) bridge[i]=bridge[i^1]=1; } else if(id[i]!=te && dfn[v[i]]<dfn[U]) lowU=min(lowU,dfn[v[i]]); return lowU; } bool vis[410000]; int cmp[410000]; bool anss[210000]; int siz[410000],cmp_sz[410000],siz2[410000]; void dfs(int U){ vis[U]=1; cmp[U]=K; for(int i=first[U];i!=-1;i=next[i]){ if(!vis[v[i]] && !bridge[i]){ dfs(v[i]); } } } int nows[410000]; void df1(int U){ vis[U]=1; for(int i=first[U];i!=-1;i=next[i]){ ++nows[K]; if(!vis[v[i]]){ df1(v[i]); } } } int jis; void df2(int U){ vis[U]=1; for(int i=first[U];i!=-1;i=next[i]){ if(!bridge[i]){ if(jis==1 && (nows[K]&1)){ anss[id[i]]=1; } } if(!vis[v[i]]){ df2(v[i]); } } } void df3(int U){ vis[U]=1; siz[U]=cmp_sz[U]; siz2[U]=1; for(int i=first[U];i!=-1;i=next[i]){ if(!vis[v[i]]){ df3(v[i]); siz[U]+=siz[v[i]]; siz2[U]+=siz2[v[i]]; } } } void df4(int root,int U){ vis[U]=1; for(int i=first[U];i!=-1;i=next[i]){ if(!vis[v[i]]){ if(jis==1 && (siz2[root]-1+siz[root])%2==1 && (siz2[v[i]]-1+siz[v[i]])%2==0 && (siz2[root]-siz2[v[i]]-1+siz[root]-siz[v[i]])%2==0){ anss[id[i]]=1; } df4(root,v[i]); } } } void df5(int U){ vis[U]=1; for(int i=first[U];i!=-1;i=next[i]){ if(cmp[U]==cmp[v[i]]){ ++cmp_sz[cmp[U]]; } if(!vis[v[i]] && cmp[U]==cmp[v[i]]){ df5(v[i]); } } } int main(){ // freopen("b.in","r",stdin); scanf("%d",&n); n=n*2+1; // n=n; memset(first,-1,sizeof(first)); for(int i=1;i<=n;++i){ scanf("%d%d",&xs[i],&ys[i]); AddEdge(xs[i],ys[i]+n,i); AddEdge(ys[i]+n,xs[i],i); } for(int i=1;i<=n*2;++i){ if(!dfn[i]){ Tarjan(i,-1); } } for(int i=1;i<=2*n;++i){ if(!vis[i]){ ++K; df1(i); nows[K]>>=1; if(nows[K]&1){ ++jis; } } } K=0; memset(vis,0,sizeof(vis)); for(int i=1;i<=2*n;++i){ if(!vis[i]){ ++K; df2(i); } } K=0; memset(vis,0,sizeof(vis)); for(int i=1;i<=n*2;++i){ if(!vis[i]){ ++K; dfs(i); } } memset(vis,0,sizeof(vis)); for(int i=1;i<=n*2;++i){ if(!vis[i]){ df5(i); cmp_sz[cmp[i]]>>=1; } } e=0; memset(first,-1,sizeof(first)); for(int i=1;i<=n;++i){ if(cmp[xs[i]]!=cmp[ys[i]+n]){ AddEdge(cmp[xs[i]],cmp[ys[i]+n],i); AddEdge(cmp[ys[i]+n],cmp[xs[i]],i); } } jis=0; memset(vis,0,sizeof(vis)); for(int i=1;i<=K;++i){ if(!vis[i]){ df3(i); if((siz2[i]-1+siz[i])&1){ ++jis; } } } memset(vis,0,sizeof(vis)); for(int i=1;i<=K;++i){ if(!vis[i]){ df4(i,i); } } for(int i=1;i<=n;++i){ puts(anss[i] ? "OK" : "NG"); } return 0; }
——The Solution By AutSky_JadeK From UESTC
转载请注明出处:http://www.cnblogs.com/autsky-jadek/