POJ 1155 TELE 树形DP(0-1背包)

题意:某电台要广播一场比赛,该电台网络是由n个网点组成的一棵树,其中m个点为客户端,
其余点为转发站。客户端i愿支付的钱为p[i],每一条边需要的花费固定,问电台在保证不亏损的情况下,
最多能使多少个客户端接收到信息?广播台所在的节点编号为1
分析:树形DP
1.用dp[u][j]表示从转发站u开始计算,满足其子树中j个顾客的最大收益 

分析节点u的孩子节点v

  a.放弃该孩子v,值不变
  b.取该孩子的若干的节点:dp[u][j-k]+dp[u][k]-cost[i][j](cost[i][j]为连通该边所需要付出的代价。)
所以状态转移方程为:

dp[u][j]=max(dp[u][j],dp[u][j-k]+dp[v][k]-cost[u][v]);

 

2.对于客户端i,dp[i][1] = p[i], 即客户端服务一个顾客获得p[i]的价值
3.最多的服务客服数为dp[1][i]中大于0的最大i值,即广播台服务i个客户不亏损.

4.设置数组num[i],表示结点i所能提供最大的用户个数,这一步属于剪枝操作,考虑到n = 3000,数据比较大,不剪枝会TLE。

View Code
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define INF 1<<29
#define maxn 3001
int dp[maxn][maxn],num[maxn];
//dp[i][j]数组表示结点i,它提供电视的用户个数j的情况下的最小费用
//num[i]表示结点i所能提供最大的用户个数
struct edge//邻接表
{
    int v, next, w;
}edge[maxn];
int head[maxn],tot;
void add(int s, int t, int w)
{
    edge[tot].v=t;
    edge[tot].w=w;
    edge[tot].next=head[s];
    head[s]=tot++;
}
void init()//邻接表初始化
{
    memset(head,-1,sizeof(head));
    tot=0;
}
int k, m ,n;
void dfs(int u)
{
    int i, j, k;
    for(i=head[u];i!=-1;i=edge[i].next)
    {
        int v = edge[i].v;
        dfs(v);
        //把子节点的状态转移到父结点,自己推一下吧
        for(j=num[u];j>=0;j--)
            for(k=1;k<=num[v];k++)
                dp[u][j+k]=max(dp[u][j+k],dp[u][j]+dp[v][k]-edge[i].w);
        num[u]+=num[v];//更新结点u所能提供的最大用户个数
    }
}
int main()
{
    int i, j, x ,y;
    while(~scanf("%d%d",&n,&m))
    {
        init();
        for(i=1;i<=n-m;i++)
        {
            scanf("%d",&k);
            while(k--)
            {
                scanf("%d%d",&x,&y);
                add(i,x,y);
            }
        }
        for(i=1;i<=n;i++)//dp[][]计算过程中会出现等于0的情况,
            for(j=1;j<=n;j++)//所以初始化要-INF,表示不通路
                dp[i][j]=-INF;
        memset(num,0,sizeof(num));
        for(i=n-m+1;i<=n;i++)
        {
            scanf("%d",&dp[i][1]);
            num[i]=1;
        }
        dfs(1);
        for(i=m;i>=0;i--)
            if(dp[1][i]>=0)
            {
                printf("%d\n",i);
                break;
            }
    }
    return 0;
}

 

 

 

posted @ 2012-08-14 20:51  To be an ACMan  Views(229)  Comments(0)    收藏  举报