Educational Codeforces Round 155 (Rated for Div. 2) E. Interactive Game with Coloring(思维题+分类讨论)

题目

n(n<=100)个点的树,读入树后,

你需要给n-1条边用最小的颜色数染色,

输出染色数k和具体每条边的染色方案

然后,每一轮,你先读入一个交互系统给出的数(1/-1/0):

1表示你已经走到根了,获胜,游戏结束

-1表示你之前的操作非法了,相当于程序wa了

0表示你当前在某个非根的点,

以下读入k个数,代表当前节点连的所有边中,

颜色为1,为2,...,为k的边的条数各有多少个

每次,你只能选择一个边的条数为1的颜色(因为你只能选择颜色,且交互系统会从颜色里随机抽一条边)

走这条边,走到父亲节点,不断和交互机交互,

每次输出你每次选的颜色,完成后续交互过程,直至当前点为根后读入1结束

思路来源

灵茶山艾府群

题解

分三种情况讨论,看到题解后,发现这个讨论还是挺自然的,但是自己手玩就玩不出来

首先,原则肯定是,我们只要能对于深度不同的点能有所区分即可,深度相同的点染一样的无所谓

1. 菊花图:即所有点都连的是根,此时只需要一种颜色,一步就走到根

2. 不难发现,我们需要让连接到父亲的边的颜色,在u这个点连接的所有边的颜色中唯一

所以,只要深度>=2了,肯定需要至少两种颜色,

那两种颜色行不行呢,考虑一条长为4的链1-2-3-4,1为根

如果点2的染色方案是1、2,点3的染色方案是2、1的话,

按照交互机的读入方式,无法区分这两个点,也就无法决定,收到这个读入后该走颜色1还是颜色2

所以,对于所有度为2的点,尝试去用相同的方式染(比如连接父亲的染成颜色1,另一端染成颜色2),类似二分图判定的过程

如果这种染边方式全局不冲突,则一定可以用两种颜色染,否则至少需要三种

Educational Codeforces Round 155 (Rated for Div. 2) E. Interactive Game with Coloring(思维题+分类讨论)_第1张图片

附一个网友给的很强的样例,用以说明这个染色的过程,1、2并不需要同层

对每个2度点染1、2,将根这个点删掉之后,考虑每个连通块独立考虑合法性

没有2度点的连通块,两种颜色循环染色即可

3. 三种的时候,就一定可以解决所有情况了,三种颜色循环染色即可

不妨第一层染1、2,第二层2、3,第三层3、1,以此类推,就可以循环下去了

代码

#include
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
typedef long long ll;
typedef double db;
typedef pair P;
#define fi first
#define se second
#define dbg(x) cerr<<(#x)<<":"< dist(l, r); return dist(gen); }
const int N=105;
int n,p[N],k,c[N],d[N];
vectore[N],f[N];
bool vis[N];
bool dfs(int u,int w){
	if(~c[u] && c[u]!=w)return 0;
	if(vis[u])return 1;
	c[u]=w;
	vis[u]=1;
	for(auto &v:f[u]){
		if(v==1)continue;
		if(!dfs(v,w^1)){
			return 0;
		}
	}
	return 1;
}
void dfs2(int u,int w){
	c[u]=w;
	for(auto &v:e[u]){
		dfs2(v,(w+1)%3);
	}
}
bool one(){
	k=1;
	return SZ(f[1])==n-1;
}
bool two(){
	k=2;
	memset(c,-1,sizeof c);
	rep(u,2,n){
		if(SZ(f[u])==2 && !dfs(u,0)){
			return 0;
		}
	}
	rep(u,2,n){
		if(!vis[u])dfs(u,0);
	}
	return 1;
}
bool three(){
	k=3;
	dfs2(1,0);
	return 1;
}
void out(){
	pte(k);
	rep(i,2,n){
		printf("%d%c",1+c[i]," \n"[i==n]);
	}
	fflush(stdout);
}
void walk(){
	int v;
	while(sci(v) && !v){
		vectorp;
		rep(i,1,k){
			sci(d[i]);
			if(d[i]==1)p.pb(i);
		}
		if(SZ(p)==1)pte(p[0]);
		else pte(p[0]==1 && p[1]==3?p[1]:p[0]);//12,23,31
		fflush(stdout);
	}
}
bool sol(){
	sci(n);
	rep(i,2,n){
		sci(p[i]);
		e[p[i]].pb(i);
		f[i].pb(p[i]);
		f[p[i]].pb(i);
	}
	if(one())return 1;
	if(two())return 1;
	return three();
}
int main(){
	sol();
	out();
	walk();
	return 0;
}

你可能感兴趣的:(思维题,交互,树,思维题,分类讨论,交互,树,二分图)