1. 程式人生 > >Explorer Bo (思維 + 樹形DP)

Explorer Bo (思維 + 樹形DP)

題意:求用最少的鏈覆蓋所有的邊用最少的總鏈長度。

思路:為了使得使用的鏈最少,我們可以知道使用的數量應該是(子葉 + 1)/ 2。 畫圖可知:當節點下的邊數是偶數時,為了將該父節點上的邊給連線上,所以連線該父節點的邊需要2條,其他情況都是1條。但是當圖中總的子葉數量為奇數時我們可以發現我們有一個可以選擇變化的點這樣以來我們就可以減少使用的總數量了。然後發現把目標點放我們把偶數節上可以減少使用的數量1,但是當你要把那個節點放在奇數點的下面的時候需要耗費1來使得同一層的邊連線進來。

#include <bits/stdc++.h>
using namespace std;

const
int maxn = 1e5 + 7; vector<int>Gra[maxn]; int son[maxn], leaf, ans, aert; void dfs(int u, int no){ son[u] = 0; for(auto v : Gra[u]){ if(v == no) continue; dfs(v, u); son[u] += son[v]; ans += (son[v]&1) ? 1: 2; } if(!son[u]) son[u] = 1,leaf ++; }
void dfsaert(int u, int no, int cnt){ aert = max(aert, cnt); for(auto v : Gra[u]) if(v != no) dfsaert(v, u, cnt + (son[v]&1 ? -1 : 1)); } int main(){ int T, n, a, b;scanf("%d", &T); while( T -- ){ scanf("%d", &n); for(int i = 1; i <= n; i ++) Gra[i].clear();
for(int i = 1; i < n; i ++){ scanf("%d%d", &a, &b); Gra[a].push_back(b); Gra[b].push_back(a); } aert = ans = leaf = 0;dfs(1, 1); if(Gra[1].size() == 1) leaf ++; if(leaf & 1) dfsaert(1, 1, 0); printf("%d\n", ans - aert); } return 0; }