苏州国决前集训Day9 模拟测试T1

该博客讨论了一种图论问题,其中涉及到在一个无重边无自环的联通无向图中进行3染色或4染色的选择。如果选择4染色,会损失40%的分数。若存在奇环,则输出奇环;否则,进行染色。博主提出了通过构造生成树来判断是否存在奇环,并给出了相应的算法实现。

有一张无重边无自环的联通无向图。你需要进行下列两件事之一:

将图 333 染色或 444 染色,即给每个点一个 111333444 中的颜色,并满足有边相连的点颜色不同。

如果你选择了进行 444 染色,你会被扣除测试点 40%40\%40% 的分数。
给出一个图中的奇环,即一个不重复的顶点序列 v1,v2⋯vkv_1,v_2⋯v_kv1,v2vkkkk 为奇数,且 viv_ivivi+1v_{i+1}vi+1vkv_kvkv1v_1v1)有边,并满足删除这个奇环中的边后图仍然联通。

可以证明两件事之一(即三染色或选出删除后联通的奇环)一定能够进行。

1≤n≤3∗105,1≤m≤3∗1051\leq n\leq 3*10^5,1\leq m\leq 3*10^51n3105,1m3105

智商题,我是傻逼

考虑随便找出一颗生成树,如果非树边中存在奇环,那么直接输出奇环,否则每个点都被两次二染色了,那就满足四染色了。

考虑如何使得非树边只在白点或黑点之间相连。

即遍历一个黑点的时候先将所有没有被遍历过的邻点染成白色,然后在进行遍历,遍历白点的时候只用遍历那些没有被遍历过的点而且还没被染成白色的即可。

显然可以保证黑点之间没有边相连,因为一定存在一个先到达,将另一个染成白色,矛盾。

#include<bits/stdc++.h>
using namespace std;

const int N=300010;
struct edge{
	int y,nex;
	bool tf;
}s[N<<1];
int n,m,first[N],col[N],ty[N],sta[N],top,len;
bool vis[N];

void ins(int x,int y){
	s[++len]=(edge){y,first[x]};first[x]=len;
}

void dfs(int x){
	vis[x]=true;
	if(col[x]){
		for(int i=first[x];i!=0;i=s[i].nex) if(!vis[s[i].y] && !col[s[i].y])
			dfs(s[i].y);
	}
	else{
		for(int i=first[x];i!=0;i=s[i].nex) if(!vis[s[i].y])
			col[s[i].y]=1;
		for(int i=first[x];i!=0;i=s[i].nex) if(!vis[s[i].y])
			dfs(s[i].y);
	}
}

void gs(int x){
	vis[x]=true;
	for(int i=first[x];i!=0;i=s[i].nex) {
		if(!vis[s[i].y]){
			ty[s[i].y]=(ty[x]^1);
			gs(s[i].y);
			if(top){
				if(top!=0){
					if(x==sta[1]) top=-top;
					else sta[++top]=x;
				}
				return ;
			}
		}
		else if(ty[x]==ty[s[i].y]){
			sta[1]=s[i].y;sta[top=2]=x;
			return ;
		}
	}
}

int main(){
	scanf("%d %d",&n,&m);
	int x,y;
	for(int i=1;i<=m;i++) scanf("%d %d",&x,&y),ins(x,y),ins(y,x);
	dfs(1);
	for(int i=1;i<=n;i++) vis[i]=false;
	for(int i=1;i<=n;i++) if(!vis[i]){
		gs(i);
		if(top!=0) break;
	}
	if(top!=0){
		top=-top;
		printf("B %d ",top);
		for(int i=1;i<=top;i++) printf("%d ",sta[i]);
	}
	else{
		printf("A ");
		for(int i=1;i<=n;i++) printf("%d ",max(col[i]*2+ty[i],1));
	}
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值