andre_joy

导航

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;
}

posted on 2012-10-09 22:18  andre_joy  阅读(488)  评论(6编辑  收藏  举报