【uva】1220 Party at Hali-Bula
1. 题目描述
公司里有$n, n \in [1, 200]$个人,他们间的关系构成树状结构。除老板外,每个员工都有唯一一个直属上司,要求从中选择尽量多的人,但是不能同时选择员工和他的直属上司,问最多能选多少人,以及可行解是否是唯一的?
2. 基本思路
这显然又是一个树形DP的题目,经典模型——树的最大独立集。《算法竞赛入门经典》中的典型例题,唯一稍微不同的是需要判断可行解是否唯一。因此,先分析状态:
(1) $dp[u][0]$表示不选$u$的最大人数,$f[u][0]$表示当前选择是否唯一,此时可以选择、也可以不选择$u$的下属;
(2) $dp[u][1]$表示选择$u$的最大人数,$f[u][1]$表示当前选择是否唯一,此时一定不能选择$u$的下属;
可以很容易推导状态转移方程:
\begin{align}
dp[u][0] &= \sum \max (dp[v][0], dp[v][1]) \\
f[u][0] &= \bigwedge \Big( (dp[v][0] \neq dp[v][1]) \wedge f[v][dp[v][0] < dp[v][1]] \Big) \\
dp[u][1] &= \sum dp[v][0] \\
f[u][1] &= \bigwedge f[v][0]
\end{align}
可以使用刷表法进行实现这个DP,经典的树形DP模型。
3. 代码
1 /* uva1220 */ 2 #include <iostream> 3 #include <sstream> 4 #include <string> 5 #include <map> 6 #include <queue> 7 #include <set> 8 #include <stack> 9 #include <vector> 10 #include <deque> 11 #include <bitset> 12 #include <algorithm> 13 #include <cstdio> 14 #include <cmath> 15 #include <ctime> 16 #include <cstring> 17 #include <climits> 18 #include <cctype> 19 #include <cassert> 20 #include <functional> 21 #include <iterator> 22 #include <iomanip> 23 #include <tr1/unordered_map> 24 using namespace std; 25 //#pragma comment(linker,"/STACK:102400000,1024000") 26 27 #define sti set<int> 28 #define stpii set<pair<int, int> > 29 #define mpii map<int,int> 30 #define vi vector<int> 31 #define pii pair<int,int> 32 #define vpii vector<pair<int,int> > 33 #define rep(i, a, n) for (int i=a;i<n;++i) 34 #define per(i, a, n) for (int i=n-1;i>=a;--i) 35 #define clr clear 36 #define pb push_back 37 #define mp make_pair 38 #define fir first 39 #define sec second 40 #define all(x) (x).begin(),(x).end() 41 #define SZ(x) ((int)(x).size()) 42 #define lson l, mid, rt<<1 43 #define rson mid+1, r, rt<<1|1 44 #define INF 0x3f3f3f3f 45 #define mset(a, val) memset(a, (val), sizeof(a)) 46 47 const int maxn = 205; 48 vi E[maxn]; 49 int fa[maxn]; 50 int dp[maxn][2]; 51 bool f[maxn][2]; 52 int n; 53 int pid; 54 map<string,int> tb; 55 map<string,int>::iterator iter; 56 57 void init() { 58 rep(i, 0, n+1) { 59 E[i].clr(); 60 fa[i] = 0; 61 } 62 tb.clr(); 63 pid = 1; 64 memset(dp, 0, sizeof(dp)); 65 memset(f, true, sizeof(f)); 66 } 67 68 inline void addEdge(int u, int v) { 69 fa[v] = u; 70 E[u].pb(v); 71 } 72 73 inline int findId(const string& s) { 74 int ret; 75 76 iter = tb.find(s); 77 if (iter == tb.end()) { 78 tb[s] = ret = pid++; 79 } else { 80 ret = iter->sec; 81 } 82 83 return ret; 84 } 85 86 void dfs(int u) { 87 int sz = SZ(E[u]), v; 88 89 dp[u][1] = 1; 90 rep(i, 0, sz) { 91 v = E[u][i]; 92 dfs(v); 93 } 94 95 // choose fa[u] choose u 96 dp[fa[u]][1] += dp[u][0]; 97 f[fa[u]][1] &= f[u][0]; 98 99 // not choose fa[u], choose or not u 100 dp[fa[u]][0] += max(dp[u][0], dp[u][1]); 101 f[fa[u]][0] &= (dp[u][0]!=dp[u][1]) & (f[u][dp[u][0]<dp[u][1]]); 102 } 103 104 void solve() { 105 dfs(1); 106 107 if (dp[1][0] > dp[1][1]) 108 printf("%d %s\n", dp[1][0], f[1][0]?"Yes":"No"); 109 else if (dp[1][0] < dp[1][1]) 110 printf("%d %s\n", dp[1][1], f[1][1]?"Yes":"No"); 111 else 112 printf("%d No\n", dp[1][1]); 113 } 114 115 int main() { 116 ios::sync_with_stdio(false); 117 #ifndef ONLINE_JUDGE 118 freopen("data.in", "r", stdin); 119 freopen("data.out", "w", stdout); 120 #endif 121 122 string su, sv; 123 int uid, vid; 124 125 while (cin>>n && n) { 126 init(); 127 cin >> su; 128 findId(su); 129 rep(i, 1, n) { 130 cin >> sv >> su; 131 132 uid = findId(su); 133 vid = findId(sv); 134 addEdge(uid, vid); 135 } 136 solve(); 137 } 138 139 #ifndef ONLINE_JUDGE 140 printf("time = %ldms.\n", clock()); 141 #endif 142 143 return 0; 144 }