luogu P1273 有线电视网
题目链接
题解
树形背包
dp[i][j]表示在以i为根的子树中,满足j个客户的需求所能获得的最大收益
代码
#include<cstdio>
#include<algorithm>
#include<cstring>
const int maxn = 3007;
//using namespace std;
inline int read() {
int x = 0,f = 1;
char c = getchar();
while(c < '0' || c > '9'){ if(c == '-') f = -1; c = getchar(); }
while(c <= '9' && c >= '0') x = x * 10 + c - '0', c = getchar();
return x * f;
}
int n , m;
struct Node {
int v , w, next;
}edge[maxn << 1];
int num , head[maxn];
inline void add_edge(int u,int v,int w) {edge[++ num].v = v,edge[num].w = w;edge[num].next = head[u];head[u] = num; }
int cost[maxn],son[maxn];
int dp[maxn][maxn];
void dfs(int u,int fa) {
dp[u][0] = 0;
if(u >= n - m + 1) {
dp[u][1] = cost[u];
son[u] = 1; return;
}
for(int num = 0,i = head[u]; i ;i = edge[i].next) {
int v = edge[i].v;
if(v == fa) continue;
dfs(v,u);
son[u] += son[v];
for(int j = son[u];j >= 1; --j)
for(int k = 0;k <= std::min(son[v],j);++ k)
dp[u][j] = std::max(dp[u][j],dp[u][j - k] + dp[v][k] - edge[i].w);
}
}
int main() {
memset(dp,-0x3f,sizeof dp);
//printf("%d\n",dp[1][0]);
n = read(),m = read();
for(int k,i = 1;i <= n - m;++ i) {
k = read();
for(int v,w,j = 1;j <= k;++ j) {
v = read(),w = read();
add_edge(i,v,w);
add_edge(v,i,w);
}
}
for(int i = n - m + 1;i <= n; ++i ) cost[i] = read();
dfs(1,1);
for(int i = m;i >= 0; -- i) if(dp[1][i] >= 0) { printf("%d\n",i);break; }
return 0;
}