B1. Village (Minimum) 樹形dp
阿新 • • 發佈:2020-09-07
題解:
關於樹的題目,一般都是從葉子節點開始考慮
對於這個題目,可以貪心的想,如果可以兩個節點兩個節點的互換,那麼就直接互換即可
如果不能兩個節點兩個節點的互換,那麼就是可能要多個節點交換。
所以用一個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; }