zoukankan      html  css  js  c++  java
  • 【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;
    }
  • 相关阅读:
    C# log4net 的配置
    C# 泛型
    Word 2013 基本概念与常用操作
    DataGridViewComboBoxColumn 事件过程分析
    C#垃圾回收机制
    Ceph分布式存储之三-S3接口编程
    .NET特性(Attribute)的应用
    24.Odoo产品分析 (三) – 人力资源板块(5) – 出勤(1)
    23.Odoo产品分析 (三) – 人力资源板块(4) – 招聘流程(1)
    22.Odoo产品分析 (三) – 人力资源板块(3) – 休假管理(1)
  • 原文地址:https://www.cnblogs.com/autsky-jadek/p/7376673.html
Copyright © 2011-2022 走看看