[樹狀dp] Perfect Service UVA1218
阿新 • • 發佈:2018-12-12
題意
給一棵無根樹,可將其中一些節點選為服務節點,每個服務節點可以服務其相鄰節點。要求每個節點只被服務一次或者被選為服務節點,求滿足要求的服務節點數量最少。
題解
本題前後用時2h,回頭來看其實也是一道簡單的樹狀dp。
在做本題時,自己的想法與紫書上的不謀而合。開始考慮時想直接借鑑最大獨立集的狀態定義(d(i)表示i子樹的答案),但之後發現如果這樣定義,那麼在轉移中就無法確認轉移合法(滿足題目要求)。通過分析要求發現,子樹根節點i是否選作服務節點是關鍵問題。參考之前的經驗,考慮用兩個狀態變數定義狀態。在確定完狀態,開始寫狀態轉移方程時發現,這樣定義狀態會導致漏解。於是再維護一個值。
。。。關於狀態和轉移的東西日後在寫。
程式碼
#include <cstdio> #include <queue> #include <cstring> #include <vector> #include <functional> #include <algorithm> #include <unordered_map> #include <string> #include <iostream> using namespace std; typedef long long ll; const int INF = 0x3f3f3f3f; const int maxn = 10000+1; vector<int> G[maxn]; int d[maxn][2], f[maxn]; int n; void dfs(int u, int fa){ if(G[u].size()==1 && G[u][0] == fa){ d[u][1] = 1; f[u] = 0; d[u][0] = maxn; return; } d[u][1] = 1; f[u] = 0; for(int i = 0; i<G[u].size(); i++)if(G[u][i] != fa){ int v = G[u][i]; dfs(v, u); d[u][1] += min(f[v], d[v][1]); f[u] += d[v][0]; } d[u][0] = INF; for(int i = 0; i<G[u].size(); i++)if(G[u][i] != fa){ int v = G[u][i]; d[u][0] = min(d[u][0], f[u]-d[v][0]+d[v][1]); } } int main(){ while(scanf("%d", &n) != EOF){ for(int i = 1; i<=n; i++) G[i].clear(); int u,v; for(int i = 1; i<n; i++){ scanf("%d%d",&u, &v); G[u].push_back(v); G[v].push_back(u); } int fg; scanf("%d", &fg); dfs(1, -1); printf("%d\n", min(d[1][1], d[1][0])); if(fg == -1) return 0; } }