【CodeVS 1163】访问艺术馆

本文介绍了一种结合树形动态规划(Tree DP)与01背包问题的算法优化方案,通过在叶节点上执行01背包算法,解决了一个包含多个展览厅,每个展览厅有多幅画作的问题,目标是在限制时间内最大化偷盗画作的总价值。文章提供了详细的代码实现,并解释了如何通过递归深度优先搜索(DFS)读取树结构,以及如何在每个节点上更新状态以达到全局最优解。

http://codevs.cn/submission/2367697/
loli蜜汁(面向高一)树形dp是这道题的改编。
改编后的题目中每个展览厅的有多个不同的画,偷画的时间和画的价值也不同,求最大价值。
需要在叶节点上做01背包。
但codevs上的这道题就简单多了,直接改了改01背包交上去A了。

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

struct nodeTreeDP {
    struct node {int nxt, to;} E[100003];
    int cnt, val[103], point[50003], f[103][603], m, tot;
    nodeTreeDP() {
        cnt = 0; tot = 1;
        memset(E, 0, sizeof(E));
        memset(f, 0, sizeof(f));
        memset(point, 0, sizeof(point));
    }
    
    void ins(int u, int v) {E[++cnt] = (node) {point[u], v}; point[u] = cnt;}
    
    void dfsread(int from) {
        int t, x;
        scanf("%d%d", &t, &x);
        ++tot;
        ins(from, tot);
        val[tot] = t << 1;
        if (x) {
            int w, c; w = 1; c = 5;
            for(int i = 1; i <= x; ++i) {
                for(int j = 600; j >= 0; --j)
                    if (j - (t << 1) - c >= 0)
                        f[tot][j] = max(f[tot][j], f[tot][j - c] + w);
            }
        } else {
            int now = tot;
            dfsread(now);
            dfsread(now);
        }
    }
    void readin() {
        int t, x;
        scanf("%d%d", &t, &x);
        val[1] = t << 1;
        if (!x) {
            dfsread(1);
            dfsread(1);
        } else {
            int w, c; w = 1; c = 5;
            for(int i = 1; i <= x; ++i) {
                for(int j = 600; j >= 0; --j)
                    if (j - (t << 1) - c >= 0)
                        f[1][j] = max(f[1][j], f[1][j - c] + w);
            }
        }
    }
    
    void TreeDP(int x) {
        for(int i = point[x]; i; i = E[i].nxt)
            TreeDP(E[i].to);
        if (!point[x]) return;
        int left = 0, right = 0;
        for(int i = point[x]; i; i = E[i].nxt) {
            if (!left) left = E[i].to;
            else right = E[i].to;
        }
        for(int top = val[x]; top <= 600; ++top) {
            int res = top - val[x];
            for(int leftnum = 0; leftnum <= res; ++leftnum) {
                int rightnum = res - leftnum;
                f[x][top] = max(f[x][top], f[left][leftnum] + f[right][rightnum]);
            }
        }
    }
    void ansit() {
        TreeDP(1);
        printf("%d\n", f[1][m]);
    }
} *T;

int main() {
    T = new nodeTreeDP;
    scanf("%d", &T->m);
    T->readin();
    T->ansit();
    return 0;
}

转载于:https://www.cnblogs.com/abclzr/p/5905559.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值