POJ 1155 TELE(树形DP)

来源:互联网 发布:数据库分组多条件查询 编辑:程序博客网 时间:2024/06/06 19:36

Description
电视台发送信号给很多用户,每个用户有愿意出的钱,电视台经过的路线都有一定费用,求电视台不损失的情况下最多给多少用户发送信号
Input
第一行为两个整数n和m分别表示路线图的节点数以及用户数(用户是叶子节点),之后n-m行第i行表示第i个节点临近的节点与其边权,每行第一个数为临近的点数k,之后2*k个数分别表示其临近的节点与其边权,最后一行m个整数表示m个用户愿意出的钱
Output
输出电视台在不亏损的情况下最多能给多少用户发送信号
Sample Input
9 6
3 2 2 3 2 9 3
2 4 2 5 2
3 6 2 7 2 8 2
4 3 3 3 1 1
Sample Output
5
Solution
树状dp。由于求的是最多多少用户,那么我们可以把用户个数当成一个状态。dp[i][j]代表i节点为根节点的子树j个用户的时候最大剩余费用。
则dp[i][j] = max(dp[i][j], dp[i][k]+dp[son][j-k]-w[i][son]);
注意
1、上面式子中的dp[i][k]必须先用一个tem[MAX]数组提取出来,因为在计算的过程中会相互影响
2、价值可能是负值,所以dp初始化的时候要初始化为负的最大值
Code

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;#define maxn 3333#define INF 11111111struct node{    int to;    int next;    int w;}edge[2*maxn];int n,m;int tol;int head[maxn];int dp[maxn][maxn];int num[maxn];int temp[maxn];void init()//初始化 {    tol=0;    memset(head,-1,sizeof(head));}void add(int a,int b,int w)//建边 {    edge[tol].w=w;    edge[tol].to=b;    edge[tol].next=head[a];    head[a]=tol++;}void dfs(int u){    for(int i=head[u];i!=-1;i=edge[i].next)    {        int v=edge[i].to;        dfs(v);        for(int j=0;j<=num[u];j++)//注意复制dp[u][j]的值,因为在后面的计算中dp[u][j]会互相影响             temp[j]=dp[u][j];        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(){    while(~scanf("%d%d",&n,&m))    {        init();//初始化         for(int i=1;i<=n-m;i++)        {            int k,v,w;            num[i]=0;//非叶子节点没有用户             scanf("%d",&k);            for(int j=0;j<k;j++)            {                scanf("%d%d",&v,&w);                add(i,v,w);//建边             }        }        for(int i=1;i<=n;i++)//初始化             for(int j=1;j<=m;j++)                dp[i][j]=-INF;        for(int i=n-m+1;i<=n;i++)        {            num[i]=1;//每个叶子节点为一个用户             scanf("%d",&dp[i][1]);//显然dp[i][1]的值即为i用户愿意出的钱         }        dfs(1);        for(int i=m;i>=0;i--)            if(dp[1][i]>=0)//找到不亏损情况下i的最大值             {                printf("%d\n",i);                break;            }    }    return 0;}
0 0