题意:给你一棵树,root为电视台,每个叶子节点为潜在的用户,其他节点为为讯号传播的中转站,每条边都有权值,如果信号发送到某个叶子节点,将收到用户交的费用,但是经过的边都要消耗费用,问最多能发送到几个用户且不亏本,不赚不亏也算。
对于每个节点,节点的子树都为一个背包,由此进行分组背包即可。
#include <stdio.h> #include <string.h> #define INF 1111111111 struct EDGE{ int to, next, val; }edge[6666]; int E, head[3333], cnt[3333], dp[3005][3005], n; void init() { memset(head, -1, sizeof(head)); E = 0; int j; for(int i = 1;i <= n; i++) { dp[i][0] = 0; for(j = 1;j <= n; j++) dp[i][j] = -INF; } } void newedge(int u, int v, int val) { edge[E].to = v; edge[E].val = val; edge[E].next = head[u]; head[u] = E++; } void dfs(int u) { if(head[u] == -1) { cnt[u] = 1; return ; } cnt[u] = 0; int i, j, k; for(i = head[u];i != -1; i = edge[i].next) { int to = edge[i].to; dfs(to); cnt[u] += cnt[to]; for(j = cnt[u];j >= 0; j--) { if(dp[u][j] == -INF) continue; for(k = 0;k <= cnt[to]; k++) if(j+k <= cnt[u] && dp[u][j] + dp[to][k]-edge[i].val > dp[u][j+k]) dp[u][j+k] = dp[u][j] + dp[to][k] - edge[i].val; } } } int main() { int i, m, k, v, val; while(scanf("%d%d", &n, &m) != -1) { init(); for(i = 1;i <= n-m; i++) { scanf("%d", &k); while(k--) { scanf("%d%d", &v, &val); newedge(i, v, val); } } for(i = n-m+1;i <= n; i++) { scanf("%d", &dp[i][1]); } dfs(1); for(i = cnt[1];i >= 0; i--) if(dp[1][i] >= 0) { printf("%d\n", i); break; } } return 0; }