P7428题解
happy_dengziyue · · 题解
1 思路
注:本题的解法正确性并未得到证明,但是能过。
我们一看题目,发现题目还有重点突出每个点最多和
然鹅,哪怕是这样,都有解,即样例。
所以我们可以得出结论:没有无解的情况。可能是因为 小 B 的孝心感天动地。
那么怎么构造呢?深搜是明显不行的。我们可以使用一种奇技淫巧。
首先,将颜色编号为
每次从队首取一个点。如果这个点已经满足要求就不去动它,否则,将它的颜色改成所有与它直接相连的点的中最稀有的颜色。
依据容斥原理,我们可以证明,这个颜色在周围只有
当然了,改完颜色后,又要判断所有与之相连的点有哪个或哪些不满足要求,压入队列。
队列为空时,答案就出来了。
2 代码与记录
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
#define max_n 25000//最大点数
#define max_m 200000//最大边数
int t;//测试数据组数
int n;//点数
int m;//边数
struct E{
int v,nx;
}e[max_m+2];//边
int ei;//下标
int fir[max_n+2];//开始路径
int micnt,micol;//周围最少的颜色的数量与那个颜色
int col[max_n+2];//颜色
queue<int>q;//队列
inline void addedge(int u,int v){
e[++ei]=(E){v,fir[u]}; fir[u]=ei;
}
int asksame(int u,int x){
int res=0;
for(int i=fir[u];i;i=e[i].nx){
if(x==col[e[i].v])++res;
}
return res;//在点u周围有res个颜色为x的点
}
inline int mi(int a,int b){
return a<b?a:b;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("P7428_1.in","r",stdin);
freopen("P7428_1.out","w",stdout);
#endif
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
ei=0;
memset(fir,0,sizeof(fir));
for(int i=1,u,v;i<=m;++i){
scanf("%d%d",&u,&v);
addedge(u,v);
addedge(v,u);
}
memset(col,0,sizeof(col));
while(!q.empty())q.pop();
for(int i=1;i<=n;++i){
if(asksame(i,col[i])>1)q.push(i);
}
while(!q.empty()){
int u=q.front();
q.pop();
if(asksame(u,col[u])<=1)continue;
micnt=8;
for(int i=0,k;i<4;++i){
k=asksame(u,i);
if(k<micnt){
micnt=k;
micol=i;
}
}
col[u]=micol;//此时必定有micnt<=1
for(int i=fir[u],v;i;i=e[i].nx){
v=e[i].v;
if(col[v]==micol&&asksame(v,micol)>1)q.push(v);
}
}
for(int i=1;i<=n;++i)putchar(col[i]+'a');
puts("");
}
return 0;
}
记录传送门
By dengziyue