1. 程式人生 > 實用技巧 >B1. Village (Minimum) 樹形dp

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\n", 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\n", num);
	for(int i=1;i<n;i++) printf("%d ", ans[i]);
	printf("%d\n", ans[n]);
	return 0;
}