constint N = 1e3 + 9; int n, ans = 0; vector<int> w(N); vector<vector<int>> g(N); vector<vector<bool>> dp(N, vector<bool>(N));
// p 是用来防止走回头路的,剩下一个 st 数组 // dp[u][x] 表示在以 u 为根的子树中,是否能选出若干节点,使得权值和恰好等于 x voiddfs(int u, int p){ if (g[u].size() == 1 && p != -1) { // 叶子节点判断 // 以叶子结点为根的子树,没有继续往下了,所以只能凑到 0 和 w[u] dp[u][0] = true; dp[u][w[u]] = true; return; }
nxt.assign(N, 0); nxt[0] = true; // 遍历当前根能凑成的所有权值 for (int s = 0; s <= w[u]; ++s) if (cur[s]) // 遍历当前遍历到的一棵子树能带来的 s + k 的新收益 for (int k = 0; k + s <= w[u]; ++k) if (dp[v][k]) nxt[s + k] = true; cur = nxt; } } dp[u] = cur; }
intmain(){ cin >> n; for (int i = 1; i <= n; i++) cin >> w[i];
for (int i = 1, u, v; i < n; i++) cin >> u >> v, g[u].push_back(v), g[v].push_back(u);
dfs(1, -1);
for (int x = w[1]; x >= 0; x--) if (dp[1][x]) { cout << x << endl; break; }