有一张无重边无自环的联通无向图。你需要进行下列两件事之一:
将图 333 染色或 444 染色,即给每个点一个 111 到 333 或 444 中的颜色,并满足有边相连的点颜色不同。
如果你选择了进行 444 染色,你会被扣除测试点 40%40\%40% 的分数。
给出一个图中的奇环,即一个不重复的顶点序列 v1,v2⋯vkv_1,v_2⋯v_kv1,v2⋯vk,kkk 为奇数,且 viv_ivi 和 vi+1v_{i+1}vi+1 (vkv_kvk 和 v1v_1v1)有边,并满足删除这个奇环中的边后图仍然联通。
可以证明两件事之一(即三染色或选出删除后联通的奇环)一定能够进行。
1≤n≤3∗105,1≤m≤3∗1051\leq n\leq 3*10^5,1\leq m\leq 3*10^51≤n≤3∗105,1≤m≤3∗105
智商题,我是傻逼
考虑随便找出一颗生成树,如果非树边中存在奇环,那么直接输出奇环,否则每个点都被两次二染色了,那就满足四染色了。
考虑如何使得非树边只在白点或黑点之间相连。
即遍历一个黑点的时候先将所有没有被遍历过的邻点染成白色,然后在进行遍历,遍历白点的时候只用遍历那些没有被遍历过的点而且还没被染成白色的即可。
显然可以保证黑点之间没有边相连,因为一定存在一个先到达,将另一个染成白色,矛盾。
#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));
}
}
该博客讨论了一种图论问题,其中涉及到在一个无重边无自环的联通无向图中进行3染色或4染色的选择。如果选择4染色,会损失40%的分数。若存在奇环,则输出奇环;否则,进行染色。博主提出了通过构造生成树来判断是否存在奇环,并给出了相应的算法实现。
310

被折叠的 条评论
为什么被折叠?



