0
点赞
收藏
分享

微信扫一扫

杭银理财杯 F-Tree Game(思维+树的欧拉序)

凉夜lrs 2022-03-25 阅读 21

题面

在这里插入图片描述

输入样例

5 3
2 1
5 2
2 4
1 3

输出样例

1 2 3

题意

给定一棵全为白色结点的树,现在需要将 k k k 个结点依次染黑,但在染黑的过程中最多只能有一个丑陋的结点,丑陋的结点定义如下(需要同时满足三个条件):

1.该点本身为黑色
2.相邻结点中至少有一个为白色
3.相邻结点中最多只有一个为黑色

上述的 2、3 条件还可转化为:若某黑色结点的相邻结点中不存在白色结点,或其相邻结点有两个及以上的黑色结点,那么该结点就不是丑陋的结点。

问:现在需要将 k k k 个结点染为黑色,若存在可行方案,则输出该方案依次染黑的结点。

思路

手模后可以发现本题一定有解,原因是从任一叶节点开始染色时,下一步可染该叶节点的父亲,此时叶节点由于相邻结点中不存在白色结点而不再丑陋。设此时的丑陋结点为 u u u ,则下一次选择 u u u 的任一相邻结点 v v v 时, u u u 都将因相邻结点有两个及以上的黑色结点而不再丑陋,由此一直迭代下去。

考虑采用树的欧拉序,当找到第一个叶结点起开始,以欧拉序输出未染色的结点,则对于样例中将所有结点染色的次序为: 4 4 4 -> 2 2 2 -> 5 5 5 -> 1 1 1 -> 3 3 3

(当然,如果不想这么麻烦的话,本题的正解是输出以任一叶子作为根的 d f s dfs dfs 序)

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=3e5+50;\

vector<int>g[N];
int n,k;
int euler[N*2],vis[N],vis2[N];
int sum[N],fat[N];
int num=0,cnt=0;

void dfs(int x,int fa){
	sum[x]=1;
	for(int i=0;i<g[x].size();i++){
		int y=g[x][i];
		if(fa==y)
			continue;
//		if(num<k){
//			cout<<y<<" ";num++;
//		}
		dfs(y,x);
		sum[x]+=sum[y];
		fat[y]=x;
	}
}

void euler_(int p){
	euler[++cnt]=p;
	vis2[p]=true;
	for(int i:g[p]){
		if(!vis2[i]){
			euler_(i);
			euler[++cnt]=p;
		}
	}
}

signed main(){
	cin>>n>>k;
	int x,y;
	for(int i=1;i<n;i++){
		cin>>x>>y;
		g[x].push_back(y);
		g[y].push_back(x);
	}
	dfs(1,0);
	euler_(1);
	
	int flag=0,num=0;
	for(int i=1;i<cnt&&num<k;i++){
		if(sum[euler[i]]==1){
			vis[euler[i]]=1;
			flag=1;
			cout<<euler[i];
			if(num!=k-1)
				cout<<" ";num++;
			continue;
		}
		if(flag==0)
			continue;
		if(vis[euler[i]]==0){
			cout<<euler[i];
			if(num!=k-1)
				cout<<" ";
				num++;
				vis[euler[i]]=1;
		}
	}
	return 0;
}

/*
10 10
1 2
1 3
1 4
4 6
4 7
5 8
5 9
5 10
2 5
*/ 
举报

相关推荐

F. 孤独的树 思维

0 条评论