码迷,mamicode.com
首页 > 其他好文 > 详细

poj1155 树上的背包

时间:2016-11-27 22:37:53      阅读:165      评论:0      收藏:0      [点我收藏+]

标签:max   子节点   span   背包   color   turn   stream   nbsp   cost   

题目链接:http://poj.org/problem?id=1155

题意:给定一棵树,1为根结点表示电视台,有m个叶子节点表示客户,有n-m-1个中间节点表示中转站,每条树边有权值。现在要在电视台播放一场比赛,每个客户愿意花费cost[i]的钱观看,而从电视台到每个客户也都有个费用,并且经过一条边只会产生一个费用。问电视台不亏损的情况最多有几个客户可以看到比赛?

思路:在树上的背包,具体看代码注释。

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define ll long long
const int maxn=3e3+5;
const int INF=0x3f3f3f3f;

struct Edge
{
    int v;
    int w;
    int next;
} edge[maxn<<1];

int dp[maxn][maxn];
int N,M;
int head[maxn];
int num[maxn],temp[maxn];  ///num数组是记录以当前节点为根节点的子树最多可以连多少个用户
int I;                     ///temp数组是为了维护当前状态,防止更新过程状态的变化影响结果

void init()
{
    I=0;
    memset(head,-1,sizeof(head));
}

void addedge(int x,int y,int w)
{
    edge[I].v=y;
    edge[I].w=w;
    edge[I].next=head[x];
    head[x]=I++;
}

void dfs(int u)    /// 如果dp[0-N][0]=-INF 结果是WA的
{
    ///这个就是保证跟用户相连的时候第一个就算是负发也要选进来,其他的正数可以弥补。
    if(u>N-M) return;  ///否则求得的不是最优解
    for(int i=head[u]; i!=-1; i=edge[i].next)
    {
        int v=edge[i].v;
        dfs(v);
        for(int k=0; k<=num[u]; k++)
            temp[k]=dp[u][k];
        for(int j=0; j<=num[u]; j++)
            for(int k=1; k<=num[v]; k++)
                dp[u][j+k]=max(dp[u][j+k],temp[j]+dp[v][k]-edge[i].w);
        num[u]+=num[v];
    }
}

int main()
{
    //freopen("in.txt","r",stdin);
    while(scanf("%d%d",&N,&M)==2)
    {
        init();
        for(int i=0; i<=N; i++) for(int j=1; j<=N; j++) dp[i][j]=-INF;///初始化时候一定要注意!
        memset(num,0,sizeof(num));
        for(int i=1; i<=N-M; i++)
        {
            int n;
            scanf("%d",&n);
            while(n--)
            {
                int a,b;
                scanf("%d%d",&a,&b);
                addedge(i,a,b);
            }
        }
        for(int i=N-M+1; i<=N; i++)
        {
            scanf("%d",&dp[i][1]);
            num[i]=1;
        }
        dfs(1);
        for(int i=M; i>=0; i--)
        {
            if(dp[1][i]>=0)
            {
                printf("%d\n",i);
                break;
            }
        }
    }
    return 0;
}

 

 

 

技术分享

poj1155 树上的背包

标签:max   子节点   span   背包   color   turn   stream   nbsp   cost   

原文地址:http://www.cnblogs.com/a-clown/p/6107087.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!