hdu 1011 树状dp。。

来源:互联网 发布:网络歌手曹菲儿 编辑:程序博客网 时间:2024/06/08 05:14

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1011

题目大意:由n个节点构成一棵树,通过每个节点有消耗((bug+19)/20),每个节点还有一个价值,开始有士兵m人,问从1节点开始往下走最多获得多少价值

题目思路:树状dp,dp[i][j]表示以i节点为根节点且消耗j能量时能获得的最大价值。状态转移方程:dp[u][j] = max(dp[u][j],dp[u][j-k]+dp[v][k])

#include<cstdio>#include<iostream>#include<cstring>using namespace std;int n,m;const int maxn = 110;struct XX{    int num,val;}nn[maxn];struct Side{    int next,v;}side[maxn*5];int node[maxn],top;void add_side(int u,int v){    side[top]=(Side){node[u],v};    node[u]=top++;}int dp[maxn][maxn],vis[maxn];void dfs(int u){    vis[u] = 1;    int num = (nn[u].num+19)/20;    for(int i=num;i<=m;i++)        dp[u][i] = nn[u].val;    for(int i=node[u];i!=-1;i=side[i].next){        int v = side[i].v;        if(vis[v])continue;        dfs(v);        for(int j = m;j>=num;j--){            for(int k = 1;k+num<=j;k++){                dp[u][j] = max(dp[u][j],dp[u][j-k]+dp[v][k]);            }        }    }}int main(){    while(cin>>n>>m){        memset(dp,0,sizeof(dp));        memset(node,-1,sizeof(node));        memset(vis,0,sizeof(vis));        top=0;        if(n==-1&&m==-1)break;        for(int i=1;i<=n;i++)            cin>>nn[i].num>>nn[i].val;        for(int i=1;i<n;i++){            int a,b;            cin>>a>>b;            add_side(a,b);            add_side(b,a);        }        if(m==0){printf("0\n");continue;}        dfs(1);        printf("%d\n",dp[1][m]);    }    return 0;}

关于状态转移的方向。。dp做的少。。然后就出问题了Orz

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

dp[u][j] 需要dp[u][j-k]去更新他的值,所以j应该是减小的,这样更新j的时候就能确保j-k是没更新过的(就是01背包那样。。)

0 0
原创粉丝点击