POJ1155 - TELE(树形DP)

题目大意

电视台要直播一场比赛,电视网络刚好形成了一棵树,其中有M个为客户端,其他的为中转站,其中中转站与中转站以及中转站与客户端之间连接都需要一定费用,每个客户i愿意支付pay[i]元钱,问电视台在不亏损的情况下,最多可以让多少个客户观看比赛

题解

每个客户要么选要么不选,和01背包差不多,只不过这是在树上进行,我们用dp[u][j]表示以u为根节点选择j个客户的能够获得的最大盈利,dp[u][j]=max(dp[u][j],dp[u][j-k]+dp[v][k])(v为u结点的子结点),最后结果就是dp[1][j](0<=j<=m)中最大的使得dp[1][j]>=0的j(保证不亏损)

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
#define MAXN 3005
#define INF 0x3f3f3f3f
struct  node
{
    int  v,next,w;
};
node edge[2*MAXN];
int head[MAXN],dp[MAXN][MAXN],cnt[MAXN],value[MAXN];
void add_edge(int u,int v,int w,int &k)
{
    edge[k].v=v;
    edge[k].w=w;
    edge[k].next=head[u];
    head[u]=k++;
}
void dfs(int u)
{
    if(head[u]==-1)
    {
        dp[u][1]=value[u];
        cnt[u]=1;
        return;
    }
    dp[u][0]=0;
    for(int i=head[u]; i!=-1; i=edge[i].next)
    {
        int v=edge[i].v;
        int w=edge[i].w;
        dfs(v);
        cnt[u]+=cnt[v];
        for(int j=cnt[u]; j>=1; j--)
            for(int k=0; k<=cnt[v]&&k<=j; k++)
                dp[u][j]=max(dp[u][j],dp[u][j-k]+dp[v][k]-w);
    }
}
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        int k=1;
        memset(head,-1,sizeof(head));
        memset(cnt,0,sizeof(cnt));
        memset(dp,-INF,sizeof(dp));
        for(int u=1; u<=n-m; u++)
        {
            int t;
            scanf("%d",&t);
            while(t--)
            {
                int v,w;
                scanf("%d%d",&v,&w);
                add_edge(u,v,w,k);
            }
        }
        for(int i=n-m+1; i<=n; i++)
            scanf("%d",&value[i]);
        dfs(1);
        for(int i=cnt[1]; i>=0; i--)
            if(dp[1][i]>=0)
            {
                printf("%d\n",i);
                break;
            }
    }
    return 0;
}

posted on 2013-11-17 18:22  仗剑奔走天涯  阅读(192)  评论(0编辑  收藏  举报

导航