POJ 3342 - Party at Hali-Bula
http://poj.org/problem?id=3342
概要
n 人の従業員からできるだけ多くの人をパーティに招待したい.
しかし,ある従業員とその上司を同時にパーティに招待しないようにしなければならない. この組織においては,Big Boss を除いてどの従業員も上司は一人しかいない.
このとき,パーティに招待できる最大の人数と,招待の仕方が唯一通りしかないかどうかを答える.
制約
- 1 <= n <= 200
解法
木構造に従って,葉のほうから
- その人を招待したときの最大人数
- その人を招待しなかったときの最大人数
を埋めていく DP.
唯一通りかどうかの判定がやや面倒.唯一通りじゃなくなるのは大きく分けて,
- 子ノードに「招待してもしなくても最大人数が変わらない」ものがあるとき
- 子ノードに「最大人数を与えるよう招待したときに,それが唯一通りでない」ものがあるとき
の2つ.
poj/3342.cc1 #include <iostream> 2 #include <vector> 3 #include <map> 4 using namespace std; 5 6 void dfs(const vector<vector<int> >& g, int n, vector<vector<int> >& dp, vector<vector<bool> >& uniq) 7 { 8 dp[n][0] = 0; dp[n][1] = 1; 9 uniq[n][0] = uniq[n][1] = true; 10 for (vector<int>::const_iterator it = g[n].begin(); it != g[n].end(); ++it) { 11 dfs(g, *it, dp, uniq); 12 if (dp[*it][0] == dp[*it][1]) { 13 dp[n][0] += dp[*it][0]; 14 uniq[n][0] = false; 15 } else if (dp[*it][0] < dp[*it][1]) { 16 dp[n][0] += dp[*it][1]; 17 uniq[n][0] = uniq[n][0] && uniq[*it][1]; 18 } else { 19 dp[n][0] += dp[*it][0]; 20 uniq[n][0] = uniq[n][0] && uniq[*it][0]; 21 } 22 dp[n][1] += dp[*it][0]; 23 uniq[n][1] = uniq[n][1] && uniq[*it][0]; 24 } 25 } 26 27 int main() 28 { 29 int N; 30 while (cin >> N && N != 0) { 31 map<string,int> m; 32 string s1; 33 cin >> s1; 34 m.insert(make_pair(s1, 0)); 35 vector<vector<int> > g(N); 36 for (int i = 0; i < N-1; i++) { 37 string s2; 38 cin >> s1 >> s2; 39 if (!m.count(s1)) { 40 m.insert(make_pair(s1, m.size())); 41 } 42 if (!m.count(s2)) { 43 m.insert(make_pair(s2, m.size())); 44 } 45 g[m[s2]].push_back(m[s1]); 46 } 47 48 vector<vector<int> > dp(N, vector<int>(2)); 49 vector<vector<bool> > uniq(N, vector<bool>(2)); 50 dfs(g, 0, dp, uniq); 51 int ans; 52 bool u; 53 if (dp[0][0] == dp[0][1]) { 54 ans = dp[0][0]; 55 u = false; 56 } else if (dp[0][0] < dp[0][1]) { 57 ans = dp[0][1]; 58 u = uniq[0][1]; 59 } else { 60 ans = dp[0][0]; 61 u = uniq[0][0]; 62 } 63 cout << ans << ' ' << (u ? "Yes" : "No") << endl; 64 } 65 return 0; 66 }