有 n 个员工,n-1个从属关系。
不能同时选择某个员工和他的直接上司,问最多可以选多少人,以及选法是否唯一。
树上的最大独立集问题。只不过多了一个判断唯一性。
dp[u][0]表示不选这个点的状态,dp[u][1]表示选这个点的状态。
如果不选 u, 那么 u点状态是由 dp[v][0] 或者 dp[v][1],大的那个点转移过来,唯一性同时也转移。
如果选 u , 那么 u点状态是由所有的 dp[v][0] 转移过来,所以只有所有的 dp[v][0]状态的都唯一时,dp[u][1]才唯一。
另外,我一直 WA 的原因在于给员工编号的时候没有判断有没有出现过,默认每行的第一个都是没有出现过的。瞎改了好久。
吸取教训。
#include <bits/stdc++.h> using namespace std; #define maxn 100010 vector<int> son[maxn], fa[maxn]; int same[maxn], dp[maxn][2], f[maxn][2]; void DP(int k) { dp[k][0] = 0, dp[k][1] = 1; f[k][1] = 1, f[k][0] = 1; for (int i = 0; i < son[k].size(); i++) { int v = son[k][i]; DP(v); dp[k][0] += max(dp[v][1], dp[v][0]); if (dp[v][1] == dp[v][0]) f[k][0] = 0; if (dp[v][1] > dp[v][0] && f[v][1] == 0) f[k][0] = 0; if (dp[v][1] < dp[v][0] && f[v][0] == 0) f[k][0] = 0; dp[k][1] += dp[v][0]; if (f[v][0] == 0) f[k][1] = 0; } } void init(int n) { for (int i = 0; i < n; i++) son[i].clear(); memset(f, 0, sizeof(0)); } int main() { int n; while(~scanf("%d", &n) && n) { init(n); map<string, int> idx; string s; cin >> s; idx[s] = 0; int id = 0; for (int i = 1; i <= n-1; i++) { string x, y; cin >> x >> y; if (!idx.count(x)) idx[x] = ++id; if (!idx.count(y)) idx[y] = ++id; son[idx[y]].push_back(idx[x]); } DP(0); int uniq = 1; if (dp[0][0] > dp[0][1] && f[0][0] == 0) uniq = 0; else if (dp[0][0] < dp[0][1] && f[0][1] == 0) uniq = 0; else if (dp[0][0] == dp[0][1]) uniq = 0; printf("%d %s\n", max(dp[0][0], dp[0][1]), uniq ? "Yes":"No"); } }