B1. Village (Minimum) 树形dp

题解:
关于树的题目,一般都是从叶子节点开始考虑
对于这个题目,可以贪心的想,如果可以两个节点两个节点的互换,那么就直接互换即可
如果不能两个节点两个节点的互换,那么就是可能要多个节点交换。
所以用一个flag来标记子节点传递给父亲节点的数量
容易得到,对于u的每一棵子树,要么传上来的节点数量是0要么是1
如果传上来节点,那么u和这些节点进行交换
如果没有,那么保留u网上传递这个节点
最后注意要特判根节点。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5+10;
typedef long long ll;
/***
题解:
关于树的题目,一般都是从叶子节点开始考虑
对于这个题目,可以贪心的想,如果可以两个节点两个节点的互换,那么就直接互换即可
如果不能两个节点两个节点的互换,那么就是可能要多个节点交换。
所以用一个flag来标记子节点传递给父亲节点的数量
容易得到,对于u的每一棵子树,要么传上来的节点数量是0要么是1
如果传上来节点,那么u和这些节点进行交换
如果没有,那么保留u网上传递这个节点
最后注意要特判根节点。
***/

int head[maxn],to[maxn<<1],nxt[maxn<<1],cnt;
void add(int u,int v){
	++cnt,to[cnt]=v,nxt[cnt]=head[u],head[u]=cnt;
	++cnt,to[cnt]=u,nxt[cnt]=head[v],head[v]=cnt;
}
int flag[maxn],ans[maxn],num;
void dfs(int u,int pre){
	// printf("u=%d pre=%d
", u,pre);
	int now = 0;
	vector<int>tmp;
	tmp.clear();
	tmp.push_back(u);
	for(int i=head[u];i;i=nxt[i]){
		int v = to[i];
		if(v == pre) continue;
		dfs(v,u);
		if(flag[v]) tmp.push_back(v);
	}
	int len = tmp.size();
	if(len>1){
		flag[u] = 0;
		num += (len-1)*2;
		for(int i=0;i<len;i++) ans[tmp[(i-1+len)%len]] = tmp[i];
	}
	else flag[u] = 1;
}



int main(){
	int n;
	num = 0;
	scanf("%d",&n);
	for(int i=1;i<n;i++){
		int u,v;
		scanf("%d%d",&u,&v);
		add(u,v);
	}
	dfs(1,0);
	if(flag[1]){
		num+=2;
		int u = to[head[1]];
		ans[1] = ans[u];
		ans[u] = 1;
	}
	printf("%d
", num);
	for(int i=1;i<n;i++) printf("%d ", ans[i]);
	printf("%d
", ans[n]);
	return 0;
}
原文地址:https://www.cnblogs.com/EchoZQN/p/13628777.html