shopping 购物 (树型dp)

【shopping题解】

10.17

思路:
考虑用树上动态规划来解决问题。
设f[u][k]表示以u为根的子树买k个物品的最小花费,且物品u使用了优惠卷;
设g[u][k]表示以u为根的子树买k个物品的最小花费,且物品u不使用优惠卷;
假设v是u的一个儿子结点,那么状态转移方程为:
f’[u][i + j] = min(f’[u][i + j], f[v][j] + f[u][i]);
f’[u][i + j] = min(f’[u][i + j], g[v][j] + f[u][i]);
g’[u][i + j] = min(g’[u][i + j], g[v][j] + g[u][i]);
理论复杂度O(n3)
树上动态规划的独特优化可以做到O(n2),详见参考代码,着重注意循环的界限以及size域的变化。

没有想到怎么把ans合并到root,于是就记忆化二分ans,感觉是不会挂的,但现实就是这么残酷。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 5010;
int n, b;
int siz[N], fa[N], c[N], d[N], f[N][N][2]; 

int main() {
    freopen("shopping.in", "r", stdin);
    freopen("shopping.out", "w", stdout);
    scanf("%d%d", &n, &b);
    for(int i=1; i<=n; i++) {
        scanf("%d%d", &c[i], &d[i]);
        if(i != 1) scanf("%d", &fa[i]);
    }
    memset(f, 63, sizeof(f));
    for(int u=1; u<=n; u++) {
        siz[u] = 1;
        f[u][0][0] = 0;
        f[u][1][0] = c[u];
        f[u][1][1] = c[u] - d[u];
    }
    for(int v=n; v>=1; v--) {
        if( fa[v] ) {
            int u = fa[v];
            for(int j=siz[u]; j>=0; j--) {
                for(int k=1; k<=siz[v]; k++) {
                    f[u][j+k][0] = min(f[u][j+k][0], f[u][j][0] + f[v][k][0]);
                    f[u][j+k][1] = min(f[u][j+k][1], f[u][j][1] + f[v][k][0]);
                    f[u][j+k][1] = min(f[u][j+k][1], f[u][j][1] + f[v][k][1]);
                }
            }
            siz[u] += siz[v];
        }
    }
    int ans = 0;
    for(int j=0; j<=siz[1]; j++) {
        if(f[1][j][0] <= b) ans = max(ans, j);
        if(f[1][j][1] <= b) ans = max(ans, j);  
    }
    printf("%d\n", ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值