1. 程式人生 > >洛谷 ~ P1273 ~ 有線電視網 (樹形揹包)

洛谷 ~ P1273 ~ 有線電視網 (樹形揹包)

在這裡插入圖片描述 在這裡插入圖片描述

思路

c[i]c[i]表示該使用者願意支出的錢 sz[u]sz[u]表示以u為根節點的子樹有多少個使用者。sz[u]+=sz[v]sz[u] += sz[v] dp[u][j]dp[u][j]表示以uu為根節點,轉發到uu個使用者利潤的最大值 如果uu為葉子結點即使用者,則dp[u][0]=c[i]dp[u][0]=c[i]dp[u][j]=max(dp[u][j],dp[u][jk]+dp[v][k]+w(u,v))(j:sz[u]>1),(k:0>min(sz[v]

,j))dp[u][j] = max(dp[u][j],dp[u][j-k]+dp[v][k]+w(u,v)),(j:sz[u]->1),(k:0->min(sz[v],j)) ans=max(ans,i)dp[1][i]>=0ans = max(ans,i)當且僅當dp[1][i]>=0

#include
<bits/stdc++.h>
using namespace std; const int MAXN = 3005; const int INF = 0x3f3f3f3f; int n, m, sz[MAXN], deg[MAXN], dp[MAXN][MAXN], c[MAXN]; vector<pair<int, int> > G[MAXN]; #define X first #define Y second void dfs(int u, int fa) { dp[u][0] = 0; if (deg[u] == 1) sz[u] = 1, dp[
u][1] = c[u]; for (auto i : G[u]) { int v = i.X, w = i.Y; if (v == fa) continue; dfs(v, u); sz[u] += sz[v]; for (int j = sz[u]; j >= 1; j--) for (int k = 0; k <= min(sz[v], j); k++) dp[u][j] = max(dp[u][j], dp[u][j-k] + dp[v][k] - w); } } int main() { memset(dp, -INF, sizeof(dp)); scanf("%d%d", &n, &m); for (int u = 1; u <= n-m; u++) { int k, v, w; scanf("%d", &k); while (k--) { scanf("%d%d", &v, &w); G[u].emplace_back(v, w); G[v].emplace_back(u, w); deg[u]++, deg[v]++; } } for (int i = n-m+1; i <= n; i++) scanf("%d", &c[i]); dfs(1, -1); int ans = 0; for (int i = 0; i <= sz[1]; i++) if (dp[1][i] >= 0) ans = i; printf("%d\n", ans); return 0; } /* 5 3 2 2 2 5 3 2 3 2 4 3 3 4 2 */