http://poj.org/problem?id=2342
某公司要举办一次晚会,但是为了使得晚会的气氛更加活跃,每个参加晚会的人都不希望在晚会中见到他的直接上司,现在已知每个人的活跃指数和上司关系(当然不可能存在环),求邀请哪些人(多少人)来能使得晚会的总活跃指数最大。
对于每一个人,都有两种情况,选,或者不选。然后选了后,他的下属就只能不选了,如果它不选,下属可能选或者不选。
这样用dfs + 记忆化搜索,就好了
每次搜索,就是要求以第cur个节点为根的子树中,其中第cur个节点的状态是sel(选或者不选)时的最大值。
记忆化搜索可以开两个数组来,一个用DFN优化,也就是时间轴,就不需要memset了。
#include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> #include <assert.h> #define IOS ios::sync_with_stdio(false) using namespace std; #define inf (0x3f3f3f3f) typedef long long int LL; #include <iostream> #include <sstream> #include <vector> #include <set> #include <map> #include <queue> #include <string> #include <bitset> int n; const int maxn = 6000 + 20; struct node { int u, v, w, tonext; }e[maxn * 2]; int num; int first[maxn]; int val[maxn]; int in[maxn], DFN; int vis[maxn][2], dp[maxn][2]; void add(int u, int v) { ++num; e[num].u = u; e[num].v = v; e[num].tonext = first[u]; first[u] = num; } int dfs(int cur, bool sel) { if (vis[cur][sel] == DFN) { return dp[cur][sel]; } vis[cur][sel] = DFN; if (sel) { int ans = 0; for (int i = first[cur]; i; i = e[i].tonext) { int v = e[i].v; ans += dfs(v, false); } dp[cur][sel] = val[cur] + ans; return val[cur] + ans; } else { int ans = 0; for (int i = first[cur]; i; i = e[i].tonext) { int v = e[i].v; ans += max(dfs(v, true), dfs(v, false)); } dp[cur][sel] = ans; return ans; } } void work() { num = 0; memset(first, 0, sizeof first); ++DFN; for (int i = 1; i <= n; ++i) scanf("%d", &val[i]); for (int i = 1; i <= n - 1; ++i) { int u, v; scanf("%d%d", &v, &u); add(u, v); in[v] = DFN; } int root = -inf; for (int i = 1; i <= n; ++i) { if (in[i] != DFN) { root = i; break; } } printf("%d ", max(dfs(root, false), dfs(root, true))); } int main() { #ifdef local freopen("data.txt", "r", stdin); // freopen("data.txt", "w", stdout); #endif while (scanf("%d", &n) != EOF && n) work(); return 0; }