//目录

POJ 1155 树形背包

题意:从一个发射站发射电视,只有叶子节点是用户,收到一部分费用,所有的边都有花费,求在不亏本的情况下,最多可以让多少用户(叶子结点)收看到电视。

分析:树形背包。

状态定义: dp(i,j) : 以 i 为根的,让 j 个用户看到电视,最大获益(可以为负数)。那么sz不再是原来的定义了。

最后遍历 j,第一个不为负数的就是答案。

状态转移:树形背包,dp(i,j) = max(d(i,j) , dp(i)(k)+dp(son,j-k)-w);

#include <algorithm>
#include <vector>
#include <cstring>
#include <cstdio>


using namespace std;

const int maxn = 3500;

struct Edge
{
    int u,v,cost;
};

vector<Edge> G[maxn];

int n,m;

int dp[maxn][maxn],tmp[maxn];
int sz[maxn];

void dfs(int u)
{

    for(int i=0; i<G[u].size(); i++)
    {
        int v = G[u][i].v;
        int cc = G[u][i].cost;
        dfs(v);

        for(int j = 0; j<=sz[u]; j++)
            tmp[j] = dp[u][j];

        for(int j=0; j<=sz[u]; j++)
        {
            for(int k=1; k<=sz[v]; k++)
            {
                dp[u][j+k] = max(dp[u][j+k],tmp[j]+dp[v][k]-cc);
            }
        }

        sz[u]+=sz[v];
    }
}

int main()
{
    //freopen("in.txt","r",stdin);
    scanf("%d%d",&n,&m);
    for(int i=1; i<=n-m; i++)
    {
        int p;
        scanf("%d",&p);
        for(int j=0; j<p; j++)
        {
            int v,c;
            scanf("%d%d",&v,&c);
            G[i].push_back((Edge)
            {
                i,v,c
            });
        }
    }

    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            dp[i][j] = -0x3f3f3f3f;
    memset(sz,0,sizeof(sz));
    for(int i=n-m+1; i<=n; i++)
    {
        int x;
        scanf("%d",&x);
        sz[i] = 1;
        dp[i][1] = x;
    }

    dfs(1);
    for(int i = m; i>=0; i--)
    {
        if(dp[1][i]>=0)
        {
            printf("%d\n",i);
            break;
        }
    }
    return 0;
}
View Code

 

posted @ 2017-08-01 09:36  小草的大树梦  阅读(202)  评论(0编辑  收藏  举报