poj 1155
地址:http://poj.org/problem?id=1155
题意:电视台发送信号给很多用户,每个用户有愿意出的钱,电视台经过的路线都有一定费用,求电视台不损失的情况下最多给多少用户发送信号。
mark:树状dp。由于求的是最多多少用户,那么我们可以把用户个数当成一个状态。dp[i][j]代表i节点为根节点的子树j个用户的时候最大剩余费用。
则dp[i][j] = max(dp[i][j], dp[i][k]+dp[son][j-k]-w[i][son]);
注意两点,第一点是上面式子中的dp[i][k]必须先用一个tem[MAX]数组提取出来,因为在计算的过程中会相互影响。第二点是价值可能是负值,所以dp初始化的时候要初始化为负的最大值。
代码:
#include <stdio.h> #include <string.h> #include <stdlib.h> const int N = 3010; const int INF = 10000000; struct { int v,w,next; }edge[3*N]; int n,m; int tot = 0; int num[N],head[N],dp[N][N],tem[N]; int max(int a, int b) {return a > b ? a : b;} void add_edge(int i, int j, int k) { edge[tot].v = j; edge[tot].w = k; edge[tot].next = head[i]; head[i] = tot++; } void dfs(int fa) { int i,j,k; for(i = head[fa]; i != -1; i = edge[i].next) { int v = edge[i].v; dfs(v); for(j = 0; j <= num[fa]; j++) tem[j] = dp[fa][j]; for(j = 0; j <= num[fa]; j++) for(k = 1; k <= num[v]; k++) dp[fa][j+k] = max(dp[fa][j+k], tem[j]+dp[v][k]-edge[i].w); num[fa] += num[v]; } } int main() { int i,j,k; int aa,bb; while(~scanf("%d%d", &n, &m)) { memset(head, -1, sizeof(head)); for(i = 1; i <= n-m; i++) { num[i] = 0; scanf("%d", &k); for(j = 0; j < k; j++) { scanf("%d%d", &aa, &bb); add_edge(i, aa, bb); } } for(i = 1; i <= n; i++) for(j = 1; j <= m; j++) dp[i][j] = -INF; for(i = n-m+1; i <= n; i++) { num[i] = 1; scanf("%d", &dp[i][1]); } dfs(1); for(i = m; i >= 0; i--) if(dp[1][i] >= 0) { printf("%d\n", i); break; } } return 0; }