UVA1218 Perfect Service
阿新 • • 發佈:2020-11-22
紫書上的樹形DP,挺香的。
\(\operatorname{Description}\)
給定一個 \(n\) 臺計算機形成的樹狀結構。要求在其中一些計算機上安裝伺服器,使得每臺不是伺服器的計算機恰好和一臺伺服器計算機相鄰。求伺服器的最小數量。
\(\operatorname{Solution}\)
考慮維護一個樹狀結構,設 \(1\) 號點為根節點,雙向建邊。
考慮樹形DP,設 \(f_u\) 為以 \(u\) 為根的子樹。
-
\(f_{u,1}\):\(u\) 是伺服器,則每個子節點可以是伺服器也可以不是。
-
\(f_{u,2}\):\(u\) 不是伺服器,但 \(u\) 的父親是伺服器,這意味著 \(u\)
-
\(f_{u,3}\):\(u\) 和 \(u\) 的父親都不是伺服器,這意味著 \(u\) 恰好有一個兒子是伺服器。
然後我們考慮如何轉移。
為了方便闡述,令 \(v\) 為 \(u\) 的子節點,定義集合 \(S\) 為 \(u\) 的所有子節點的集合。
首先可以寫出:
\[f_{u,0}=\sum_{v∈S}\min(f_{v,0},f_{v,1})+1 \]\[f_{u,1}=\sum_{v∈S}f_{v,2} \]而 \(f_{v,2}\) 的轉移稍微複雜一點,考慮遍歷 \(v\),則當前 \(v\) 為 \(u\) 子節點的唯一伺服器,設其他所有子節點為 \(v'\)
由於 \(f_{u,2}\) 的轉移是 \(O(n^2)\) 的,故考慮優化。
看到上文中的 \(f_{u,1}=\sum_{v∈S}f_{v,2}\),所以對柿子進行處理後:
\[f_{u,2}=\min(\sum_{v∈S}(f_{v,0}+f_{u,1}-f{v,2})) \]考慮最後的答案,由於根結點並沒有父親節點,故為 \(\min(f_{1,0},f_{1,2})\)
\(\operatorname{Code}\)
#include<bits/stdc++.h> using namespace std; const int N=10005; const int Inf=10005; int n,f[N][3]; vector <int> q[N]; void dfs(int u, int fa) { f[u][0]=1; f[u][1]=0; f[u][2]=Inf; for(int i=0;i<q[u].size();i++) { if(q[u][i]==fa) continue; int v=q[u][i]; dfs(v,u); f[u][0] += min (f[v][1],f[v][0]); f[u][1] += f[v][2]; f[u][2] = min (f[u][2],f[u][1]-f[v][2]+f[v][0]); } } void Clear() {for(int i=1;i<=n;i++) q[i].clear();} int main() { while (cin >> n) { Clear(); for(int i=1;i<n;i++) { int x,y; cin >> x >> y; q[x].push_back(y); q[y].push_back(x); } dfs(1,0); printf("%d\n",min (f[1][0],f[1][2])); int d; cin >> d; if(d==-1) break; } return 0; }