UVa 1220 - Party at Hali-Bula(樹形DP)
阿新 • • 發佈:2018-03-23
style sin col 轉移 time ali main 分析 hal
二、設d(u,1)和f(u,1)表示以u為根的子樹中,選u點能得到的最大人數以及方案唯一性。相應地,狀態轉移方程也有兩套。
三、d(u,1)的計算:因為選了u,所以u的子結點都不能選,故d(u,1) = sum{d(v,0) | v是u的子結點}。當所有f(v,0)=1時f(u,1)=1。
四、d(u,0)的計算:因為u沒有選,所以每個子結點v可選可不選,即d(u,0) = sum{ max(d(v,0), d(v,1)) }。
什麽情況下方案是唯一的呢?首先,如果某個d(v,0)和d(v,1)相等,則不唯一;
其次,如果max取到的那個值對應的f=0,方案也不唯一(如d(v,0) > d(v,1) 且f(v,0)=0,則f(u,0)=0)。
鏈接:
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3661
題意:
公司裏有n(n≤200)個人形成一個樹狀結構,即除了老板之外每個員工都有唯一的直屬上司。
要求選盡量多的人,但不能同時選擇一個人和他的直屬上司。問:最多能選多少人,以及在人數最多的前提下方案是否唯一。
分析:
本題幾乎就是樹的最大獨立集問題,不過多了一個要求:判斷唯一性。
一、設d(u,0)和f(u,0)表示以u為根的子樹中,不選u點能得到的最大人數以及方案唯一性(f(u,0)=1表示唯一,0表示不唯一)。
二、設d(u,1)和f(u,1)表示以u為根的子樹中,選u點能得到的最大人數以及方案唯一性。相應地,狀態轉移方程也有兩套。
三、d(u,1)的計算:因為選了u,所以u的子結點都不能選,故d(u,1) = sum{d(v,0) | v是u的子結點}。當所有f(v,0)=1時f(u,1)=1。
四、d(u,0)的計算:因為u沒有選,所以每個子結點v可選可不選,即d(u,0) = sum{ max(d(v,0), d(v,1)) }。
什麽情況下方案是唯一的呢?首先,如果某個d(v,0)和d(v,1)相等,則不唯一;
其次,如果max取到的那個值對應的f=0,方案也不唯一(如d(v,0) > d(v,1) 且f(v,0)=0,則f(u,0)=0)。
代碼:
1 #include <cstdio> 2 #include <map> 3 #include <string> 4 #include <vector> 5 using namespace std; 6 7 const int UP = 200 + 5; 8 int cid, d[UP][2]; // d數組表示以f為根的子樹中,選或不選f點能得到的最大人數 9 bool u[UP][2]; // u數組表示以f為根的子樹中,選或不選f點的方案唯一性 10 map<string, int> M; 11 vector<int> son[UP]; 12 13 int id(char* s){ 14 if(M.count(s)) return M[s]; 15 return M[s] = cid++; 16 } 17 18 int dp(int f, int p){ 19 d[f][p] = p; 20 u[f][p] = true; 21 for(int i = 0; i < son[f].size(); i++){ 22 int b = son[f][i]; 23 if(p == 1){ 24 d[f][1] += dp(b, 0); 25 if(!u[b][0]) u[f][1] = false; 26 } 27 else{ 28 d[f][0] += max(dp(b, 0), dp(b, 1)); 29 if(d[b][0] == d[b][1]) u[f][0] = false; 30 else if(d[b][0] > d[b][1] && !u[b][0]) u[f][0] = false; 31 else if(d[b][1] > d[b][0] && !u[b][1]) u[f][0] = false; 32 } 33 } 34 return d[f][p]; 35 } 36 37 int main(){ 38 int n; 39 char f[999], b[999]; 40 while(scanf("%d", &n) && n){ 41 cid = 0; M.clear(); 42 for(int i = 0; i < n; i++) son[i].clear(); 43 44 scanf("%s", f); id(f); 45 for(int i = 1; i < n; i++){ 46 scanf("%s%s", b, f); 47 son[id(f)].push_back(id(b)); 48 } 49 50 printf("%d ", max(dp(0, 0), dp(0, 1))); 51 bool ok = (d[0][0]>d[0][1]&&u[0][0]) || (d[0][1]>d[0][0]&&u[0][1]); 52 printf("%s\n", ok ? "Yes" : "No"); 53 } 54 return 0; 55 }
UVa 1220 - Party at Hali-Bula(樹形DP)