hdu1561树形dp+依赖背包

题目大意:ACboy很喜欢玩一种战略游戏,在一个地图上,有N座城堡,每座城堡都有一定的宝物,在每次游戏中ACboy允许攻克M个城堡并获得里面的宝物。但由于地理位置原因,有些城堡不能直接攻克,要攻克这些城堡必须先攻克其他某一个特定的城堡。你能帮ACboy算出要获得尽量多的宝物应该攻克哪M个城堡吗?


思路:咋一看就想到了依赖背包,依赖关系的时候建个树。dp[i][j]表示以i为根节点的子树加自己选取j个城堡是的最大值,则有dp[u][j] = max(dp[u][j] , dp[u][k] + dp[E[i].v][j-k]);

另外:因为有一个自己加入的根节点0,所以答案是dp[0][m+1].dp时上限是m+1。


#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <iomanip>

using namespace std;
//#pragma comment(linker, "/STACK:102400000,102400000")
#define maxn 305
#define MOD 1000000007
#define mem(a , b) memset(a , b , sizeof(a))
#define LL long long
#define INF 100000000

int n , m;
struct edge
{
    int u , v , w;
    int next;
}E[maxn];
int head[maxn];
int dp[maxn][maxn];
int id;

void add(int u , int v , int w)
{
    E[id].u = u;
    E[id].v = v;
    E[id].w = w;
    E[id].next = head[u];
    head[u] = id++;
}

void solve(int u)
{
   // cout << u << " " << head[u] << endl;
    if(head[u] < 0) return ;
    for(int i = head[u] ; i >= 0 ; i = E[i].next)
    {
        solve(E[i].v);
        for(int j = m ; j > 1 ; j--)
        {
            for(int k = 1 ; k < j ; k ++)
            {
              //  cout << u << " " << j << " " << k <<  " " << dp[u][j] << " " << dp[u][k] << " " << E[i].v << " " << dp[E[i].v][j-k]<< endl;
                dp[u][j] = max(dp[u][j] , dp[u][k] + dp[E[i].v][j-k]);
              //  cout << u << " " << j << " " << k <<  " " << dp[u][j] << " " << dp[u][k] << " " << E[i].v << " " << dp[E[i].v][j-k]<< endl;
            }
        }
    }
}

int main()
{
    while(scanf("%d %d" , &n , &m) != EOF && ( n || m))
    {
        id = 0;
        mem(head , -1);
        mem(dp , 0);
        int a , b;
        m++;
        for(int i = 1 ; i <= n ; i ++)
        {
            scanf("%d %d" , &a , &b);
            add(a , i  , b);
            for(int j = 1 ; j <= m ; j ++)
                dp[i][j] = b;
              //  dp[i+1][0] = b;
        }
        solve(0);
        printf("%d\n" , dp[0][m]);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值