zoukankan      html  css  js  c++  java
  • luoguP4429 [BJOI2018]染色

    一个无向图,每个点设置一个大小为(2)的颜色集合,表示这个点可以选择两种颜色其中之一。

    给你这张无向图,问是否对于设置集合的任意方案,都可以染色使得每条边连接的两个点颜色不同。

    (nle 10^4,mle 2*10^4)


    奇怪的结论题/构造题。然而官方数据好水啊真不知道那年bj人是怎么挺过来的。洛谷上加了hack数据,这是我标题放了洛谷的原因。

    对于每个连通块分别处理。显然如果图不是二分图就NO。然后去掉所有度数小于等于(1)的点。

    考虑使用三种颜色或四种颜色(四种颜色的情况比较少)。(经过下面的分析得到筛剩下的情况中用更多的颜色没有什么卵用。)

    发现结论1:如果存在偶环,那么可以用一种构造方案,使得块中的某个点选择一种颜色时一定不合法(或者说强制选另一种颜色)。

    可以考虑(z o y)经过偶环且(y)在偶环上。设(x)为路径上的第一个偶环上的点。此时(x o y)有两条路径。不妨设(x)((A,B))(它的状态可以直接被(z)钦定),当选(A)时,(x)的两个后继都是固定的颜色,路径上的每个点的颜色都被前一个点决定;一直到(B)的前驱,发现两个前驱选的颜色互不相同而且也是(B)的集合中的颜色。所以(x)(A)不合法,但此时并不能同时决定选(B)不合法。

    推论1:如果存在两个不在边相交的偶环,那么一定不合法。

    可以找到中间的一个点(z)。如果两个环只有一个交点,构造方案钦定(z)(A)时环甲不合法,选(B)时环乙不合法。如果环有两个交点,具体是说两个偶环上的(y)重合,此时类似,但需要用到四种颜色。

    结论2:考虑两个相交的偶环,找到两个三度点(u,v)。此时(u o v)有三条不相交的路径,当且仅当路径长度分别为(2,2,偶数)时合法。

    其实只需要证明(1,3,3)不合法,和(2,4,4)不合法。更长的情况相当于在某个路径上加偶数个点,可以钦定一下使得经过了偶数个点之后状态不变。

    先证前者。比如下面这个图(四相邻格子有边),如此构造即可。

    ((B,C)) ((A,B))
    ((A,C)) ((A,C))
    ((A,B)) ((B,C))

    再证后者。比如下面(除了第二行没有横边外四相邻有边)。

    ((A,C)) ((A,B)) ((A,B))
    ((B,C)) (没横边)((A,B))(没横边) ((A,C))
    ((A,B)) ((A,B)) ((B,C))

    推论2:(mge n+2)时一定不合法,(mle n)时一定合法。(m=n+1)时需要用上面条件判断。

    只用证(m=n+2),如果所有的环两两相交时,一定存在不满足(2+2+偶数)的子图。具体考虑从(m=n+1)的合法情况中加入一条边,那么相当于在(2+2+偶数)的子图中加入一条路径(长度任意)连接其中两个点。讨论一下加入的路径连接哪里(此处省略具体过程),最终证明出都不合法。

    按照以上的结论判断即可。


    using namespace std;
    #include <bits/stdc++.h>
    #define N 100005
    #define M 200005
    int n,m;
    struct EDGE{
    	int to;
    	EDGE *las;
    } e[M*2];
    int ne;
    EDGE *last[N];
    void link(int u,int v){
    	e[ne]={v,last[u]};
    	last[u]=e+ne++;
    }
    int ans;
    int c[N];
    int cntd,cnte;
    int q[N];
    void color(int x){
    	q[cntd++]=x;
    	for (EDGE *ei=last[x];ei;ei=ei->las,cnte++)
    		if (c[ei->to]==-1)
    			c[ei->to]=c[x]^1,color(ei->to);
    		else if (c[x]^c[ei->to]^1)
    			ans=0;
    }
    int deg[N];
    void work(){
    	static queue<int> que;
    	for (int i=0;i<cntd;++i){
    		deg[q[i]]=0;
    		for (EDGE *ei=last[q[i]];ei;ei=ei->las)
    			deg[q[i]]++;
    		if (deg[q[i]]<=1)
    			que.push(q[i]);
    	}
    	while (!que.empty()){
    		int x=que.front();
    		que.pop();
    		for (EDGE *ei=last[x];ei;ei=ei->las)
    			if (--deg[ei->to]==1)
    				que.push(ei->to);
    	}
    	int nei[2][3],k[2]={0,0},c=0;
    	for (int i=0;i<cntd;++i){
    		if (deg[q[i]]==4){
    			ans=0;
    			return;
    		}
    		if (deg[q[i]]==3){
    			for (EDGE *ei=last[q[i]];ei;ei=ei->las)
    				if (deg[ei->to]>1)
    					nei[c][k[c]++]=ei->to;
    			assert(k[c]==3);
    			sort(nei[c],nei[c]+3);
    			c++;
    		}
    	}
    	assert(c==2);
    	int i=0,j=0,cnt=0;
    	while (i<k[0] && j<k[1])
    		if (nei[0][i]<nei[1][j])
    			i++;
    		else if (nei[0][i]>nei[1][j])
    			j++;
    		else
    			i++,j++,cnt++;
    	ans&=(cnt>=2);
    }
    int main(){
    	freopen("in.txt","r",stdin);
    	int T;
    	scanf("%d",&T);
    	while (T--){
    		scanf("%d%d",&n,&m);
    		memset(last,0,sizeof(EDGE*)*(n+1));
    		ne=0;
    		for (int i=1;i<=m;++i){
    			int u,v;
    			scanf("%d%d",&u,&v);
    			link(u,v);
    			link(v,u);
    		}
    		memset(c,255,sizeof(int)*(n+1));
    		ans=1;
    		for (int i=1;i<=n && ans;++i)
    			if (c[i]==-1){
    				cntd=cnte=0;
    				c[i]=0,color(i);
    				cnte/=2;
    				if (cnte>=cntd+2)
    					ans=0;
    				else if (cnte==cntd+1)
    					work();
    			}
    		printf("%s
    ",ans?"YES":"NO");
    	}
    	return 0;
    }
    
  • 相关阅读:
    jQuery插件主要有两种扩展方式
    系统负载测试工具-LoadRunner
    安全扫描工具-AppScan
    newinstance()和new有什么区别?(转)
    类的加载、连接和初始化 (转)
    tar 基础
    了解【重放攻击】
    DDLDMLDCLDQL
    web.xml的配置问题
    组合与聚合
  • 原文地址:https://www.cnblogs.com/jz-597/p/14276555.html
Copyright © 2011-2022 走看看