hdu 1561 树形背包 选k个最大价值

http://blog.csdn.net/dellaserss/article/details/8799730

这题其实和上一题思路是一样的,一个0节点作为根节点,通过剩余量来遍历子树。

#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <stack>
#include <queue>
#include <cctype>
#include <vector>
#include <iterator>
#include <set>
#include <map>
#include <sstream>
using namespace std;

#define mem(a,b) memset(a,b,sizeof(a))
#define pf printf
#define sf scanf
#define spf sprintf
#define pb push_back
#define debug printf("!\n")
#define MAXN 205
#define MAX(a,b) a>b?a:b
#define blank pf("\n")
#define LL long long
#define ALL(x) x.begin(),x.end()
#define INS(x) inserter(x,x.begin())
#define pqueue priority_queue
#define INF 0x3f3f3f3f

int n,m;

struct node
{
    int y,next;
}tree[1000];

int head[MAXN],dp[MAXN][MAXN],ptr=1;

int sum[MAXN],vl[MAXN],vis[MAXN];

void add(int x,int y)
{
    tree[ptr].y = y;
    tree[ptr].next = head[x];
    head[x] = ptr++;
}

void dfs(int root)
{
    if(vis[root]) return;
    int i,j,k;
    vis[root] = sum[root] = 1;
    int tot = 0;

    for(i=head[root]; i!=-1; i=tree[i].next)
    {
        int p = tree[i].y;

        if(!vis[p])
        {
            dfs(p);
            sum[root]+=sum[p];
            tot++;
            //pf("i%d p%d tot%d sum%d\n",root,p,tot,sum[root]);
        }
    }

    dp[root][1] = vl[root];

    for(i=head[root]; i!=-1; i=tree[i].next)
    {
        int p = tree[i].y;

        for(j = sum[root];j>1;j--)
        {
            for(k = 1;k<j;k++)
            {
                if(dp[root][k]!=-1 && dp[p][j-k]!=-1)
                {
                    dp[root][j] = max(dp[root][j],dp[root][k]+dp[p][j-k]);
                    //pf("i%d j%d k%d p%d dp%d\n",root,j,k,p,dp[root][j]);
                }
            }
        }
    }
}

int main()
{
    int i,j,k,a,b;
    while(~sf("%d%d",&n,&m) && m+n>0)
    {
        mem(head,-1);
        ptr = 1;

        for(i=1;i<=n;i++)
        {
            sf("%d%d",&a,&b);
            add(i,a);
            add(a,i);
            vl[i] = b;
        }
        mem(dp,-1);
        mem(vis,0);
        dfs(0);
        pf("%d\n",dp[0][m+1]);
    }
    return 0;
}

但我发现这道题因为要统计子节点数量,其实用邻接表更方便一些:(但速度会慢很多)

#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <stack>
#include <queue>
#include <cctype>
#include <vector>
#include <iterator>
#include <set>
#include <map>
#include <sstream>
using namespace std;

#define mem(a,b) memset(a,b,sizeof(a))
#define pf printf
#define sf scanf
#define spf sprintf
#define pb push_back
#define debug printf("!\n")
#define MAXN 205
#define MAX(a,b) a>b?a:b
#define blank pf("\n")
#define LL long long
#define ALL(x) x.begin(),x.end()
#define INS(x) inserter(x,x.begin())
#define pqueue priority_queue
#define INF 0x3f3f3f3f

int n,m;

struct node
{
    int y,next;
}tree[1000];

int head[MAXN],dp[MAXN][MAXN],ptr=1;

int sum[MAXN],vl[MAXN],vis[MAXN];

vector<int> son[1000];

void dfs(int root)
{
    int i,j,k;

    for(i=0;i<son[root].size();i++)
    {
        int p = son[root][i];

        if(son[p].size()>0) dfs(p);

        for(j=m;j>1;j--)
        {
            for(k=1;k<j;k++)
            {
                dp[root][j] = max(dp[root][j],dp[root][k] + dp[p][j-k]);
                //pf("i%d j%d k%d p%d dp%d\n",root,j,k,p,dp[root][j]);
            }
        }
    }
}

int main()
{
    int i,j,k,a,b;
    while(~sf("%d%d",&n,&m) && m+n>0)
    {
        mem(dp,0);
        m++;

        for(i=0;i<=n;i++) son[i].clear();

        for(i=1;i<=n;i++)
        {
            sf("%d%d",&a,&b);
            son[a].pb(i);
            for(j=1;j<=m;j++) dp[i][j] = b;
        }
        dfs(0);
        pf("%d\n",dp[0][m]);
    }
    return 0;
}
时间: 2024-12-07 13:58:51

hdu 1561 树形背包 选k个最大价值的相关文章

HDU 1561 (树形DP+背包)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1561 题目大意:从树根开始取点.最多取m个点,问最大价值. 解题思路: cost=1的树形背包. 有个虚根0,取这个虚根也要cost,所以最后的结果是dp[0][m+1]. 本题是cost=1的特殊背包问题,在两个for循环上有一个优化. for(f+1...j....cost) for(1....k...j-cost) 其中f为当前已经dfs子结点个数.之所以+1,是因为根要预留一个空间. f+

hdu 1561 树形dp+分组背包

题意:就是给定n个点,每个地点有value[i]的宝物,而且有的宝物必须是另一个宝物取了才能取,问取m个点可以获得的最多宝物价值. 一个子节点就可以返回m个状态,每个状态表示容量为j(j<=m)时选最多的宝物,而一个子节点中只可以选择一个状态进行转移,每个节点有若干个子节点,问题就转换为分组背包,几个子节点就是几个分组背包,体积是选几个地点,价值是宝物价值. 状态转移方程: dp[v][1] = Money[v]; (v为叶子节点)                    dp[v][j] = m

hdu 1561 树形dp+0-1背包

1 /* 2 根据先后关系,可以建立一棵树 3 dp[i][j]表示第i个节点选j个的最大值 4 dp[i][j]=max(sigma(dp[c[i][ki]])) 5 sigma(dp[c[i][ki]])表示从i的儿子节点中一共选取j个点的最大值 6 */ 7 /*#include <iostream> 8 #include <cstdio> 9 #include <cstring> 10 #include <vector> 11 using names

HDU 1561 树形DP背包问题

这是自己第一道背包上树形结构问题,不是很理解这个概念的可以先看看背包九讲 自己第一次做,看了一下别人的思路,结合着对简单背包问题的求解方式自己一次AC了还是有点小激动的 题目大意是: 攻克m个城市,每个城市都有对应数量的宝贝,攻克某一个城市必须保证其对应的某一个特定城市已经被攻克,希望得到最多数量的宝贝 很容易根据题目画出一个对应关系的树形结构,每个节点都有一个对应的宝物的数量 我们用dp[i][j]存 i 号节点它下方子树中 有 j 个城市被攻克时得到的宝物最大数量 , 此时的 i 号是没有被

HDU 1561 树形DP入门

The more, The Better Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 6011    Accepted Submission(s): 3555 Problem Description ACboy很喜欢玩一种战略游戏,在一个地图上,有N座城堡,每座城堡都有一定的宝物,在每次游戏中ACboy允许攻克M个城堡并获得里面的宝物

hdu 1011 树形背包

http://blog.csdn.net/libin56842/article/details/9876503 这道题和poj 1155的区别是: poj1155是边的价值,所以从边的关系入手 hdu1011是点的价值,从点的关系入手,所以node没有val,在dp时不用记录叶子节点个数,只需要对每个点用背包遍历一遍即可 dp[root][j+k] = max(dp[root][j+k],dp[p][k]+dp[root][j]) dp表示在i点放j人能得到的能量 #include <iostr

hdu 1561 树形dp

又一道树形dp,发现其实树形dp长得都挺像的. 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 6 const int INF = -9999999; 7 const int N = 201; 8 int dp[N][N]; 9 int head[N]; 10 int value[N]; 11 int n, m, e; 12 13 void i

HDU 1561 ——The more, The Better(有依赖的树形DP)

题目分析: 攻占城堡所能获得的最多宝物,但是有个限制,要想攻占某个城堡前必须先攻占另一个城堡 思路: 建图,新建一个根节点为0,那么题目就变为要想取得子节点必须先取得它的父亲节点 今天为了解决这个问题,看了下背包九讲中的有依赖的背包,刷了道模板题. 大概思路是:要想取得附件必须先取主件,主件要么取,要么不取,取得话要怎么分配给附件,用01背包处理附件,然后再把每个主件分组背包 树形的依赖主要是附件是个集合,附件还有附件.森林的概念 根据DP的思想,我们先dfs到叶,01背包操作 即可.只是每次d

HDU 1011 (树形DP+背包)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1011 题目大意:树上取点,先取父亲,再取儿子.每个点,权为w,花费为cost,给定m消费总额,求最大权和. 解题思路: 树形背包模板题.首先建一个无向图. 每个点的cost=(bug[root]+19)/20,即虫子数不满20也要派一个人. 用dp[i][j]表示以i为根的子树中,花费为j的最大权和. 转移方程:dp[i][j]=max(dp[i][j],dp[i][j-k]+dp[t][k]),