赞
踩
有一张
n
(
3
≤
n
≤
3
⋅
1
0
5
)
n(3\le n\le 3\ ·10^5)
n(3≤n≤3 ⋅105) 个点
m
(
3
≤
m
≤
5
⋅
1
0
5
)
m(3\le m\le 5\ ·10^5)
m(3≤m≤5 ⋅105) 条边的简单无向图(保证初始连通),需要将每个顶点染为红绿蓝三种颜色之一。然后对于每条边,若其两个端点颜色一样,则边也变成对应颜色,否则保持黑色。
基础目标:
在完成基础目标的前提下,还可以完成以下额外目标:
如下所示,左图是染色前,右图是按某种方式染色后的结果,其满足基础目标,每种颜色的顶点数相同,绿色节点的出现次数最多且相邻边均为黑色,因此满足两个额外条件。
(图片摘自原题)
给定未染色的图,求至少完成一个额外目标的方案,或判断无解。
首先考虑基础目标,我们可以将原图删去一些边,使得剩下的{V,E}构成一棵树,然后保证树上相邻的点都为异色即可。
我们以任意点为跟跑出一棵Tarjan树,然后按红绿相间的方式对整张图进行初步染色,现在我们完成了基础目标。
然后考虑额外目标:
根据以上策略与题目的数据限制,可以保证不会出现无解的情况(没有1.和2.以外的情况)。
#include<bits/stdc++.h> #define ll long long #define For(i,n,m) for(int i=n;i<=m;i++) #define FOR(i,n,m) for(int i=n;i>=m;i--) using namespace std; void read(int &x){ int ret=0; char c=getchar(),last=' '; while(!isdigit(c))last=c,c=getchar(); while(isdigit(c))ret=ret*10+c-'0',c=getchar(); x=last=='-'?-ret:ret; } const int MAXN=3e5+5; int T,n,m,r,g,vis[MAXN],leaf[MAXN];//r记录红色点数,g记录绿色点数,vis记录颜色(1红0绿2蓝),leaf标记是否为叶节点 vector<int>e[MAXN],dfe[MAXN];//e记录图边,dfe记录Tarjan跑dfs过程中得到的树边 void Tarjan(int x,int fa,int c){ if(c)r++;//c为1染红色,增加红色计数 else g++;//c为0染绿色,增加绿色计数 vis[x]=c;//颜色标记 int son; bool isleaf=true;//标记是否为Tarjan树中的叶节点 For(i,0,e[x].size()-1){ son=e[x][i]; if(~vis[son])continue;//若不是-1,即已访问过,则跳过回边 Tarjan(son,x,c^1);//先进行递归,注意c^1间接染色 dfe[x].push_back(son);//存入树边 isleaf=false;//若有子节点,则非叶节点 } leaf[x]=isleaf?1:0;//标记是否为叶节点 } void paint(int x){ if(dfe[x].empty()){//叶节点 if(vis[x]==1){//原颜色为红 if(r>n/3)r--,vis[x]=2;//若红色点数仍超量,染色为蓝色 } else{//原颜色为绿 if(g>n/3)g--,vis[x]=2;//若绿色点数仍超量,染色为蓝色 } return; } int son; bool f=true;//标记非叶节点是否可染色为蓝色 For(i,0,dfe[x].size()-1){ son=dfe[x][i]; paint(son);//先递归染色较深的节点 if(vis[son]==2)f=false;//若有子节点已经染色为蓝色,则该节点不可再染色 } if(f){//可染色 if(vis[x]==1){//原颜色为红 if(r>n/3)r--,vis[x]=2;//若红色点数仍超量,染色为蓝色 } else{//原颜色为绿 if(g>n/3)g--,vis[x]=2;//若绿色点数仍超量,染色为蓝色 } } } int main() { read(T); while(T--){ read(n),read(m); int u,v; memset(vis,-1,sizeof(vis));//初始化颜色标记为-1 For(i,1,n)e[i].clear(),dfe[i].clear();//清空边 while(m--){ read(u),read(v); e[u].push_back(v); e[v].push_back(u); } r=g=0;//清空颜色计数 Tarjan(1,-1,1); if(r<=n/3*2&&g<=n/3*2){//选择额外目标1 paint(1);//染色使得各颜色点数相等 For(i,1,n)printf("%c",vis[i]==1?'R':(vis[i]==0?'G':'B')); puts(""); } else{//选择额外目标2 For(i,1,n)if(leaf[i])vis[i]=2;//将全部叶节点染色为蓝色,使得蓝点形成独立集且大小最大 For(i,1,n)printf("%c",vis[i]==1?'R':(vis[i]==0?'G':'B')); puts(""); } } return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。