At_dp_x Tower

题目链接

贪心 + Dp

Part1

看上去很像背包,但是发现最后答案和堆放的顺序有关,很容易想到状压,但是复杂度不允许。

而且发现如果一个一个向上放,当前决策会有后效性,题目也不允许在开一维状态。

Part2

对于后效性,我们可以每次把箱子放在最下面,就没有后效性了。

重点是解决顺序问题,考虑两个箱子 \(i ,j\) 在什么情况下,其中一种会优先放在下面。我们想让在这个箱子上面放的重量尽量多,那么有 \(s_i-w_j \geqslant s_j-w_i\) ,那么 \(s_i+w_i \geqslant s_j+w_j\) , 那我们按照 \(s+w\) 从小到大(越大的越放在下面)排序即可。

Part3

剩下的就是普通 \(0/1\)背包, 设 \(dp_i\) 表示当前重量为 \(i\) 的最大价值,那么有:

\[dp_{j+w_i}=\max(dp_{j+w_i} , dp_j+v_i) \]

复杂度 \(\Theta(n^2)\)

Code
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

#define int long long

const int N=1e3+10;
const int M=2e4+10;

using namespace std;

inline int read() {
    int f=1, x=0;
    char ch=getchar();
    while(ch>'9' || ch<'0') {
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0' && ch<='9') {
        x=(x<<3)+(x<<1)+(ch^48);
        ch=getchar();
    }
    return f*x;
}

inline void write(int x) {
    cout<<x; putchar('\n');
}

int n;
struct node {
    int w, s, v;
}a[N];

inline bool cmp(node x,node y) {
    return x.w+x.s < y.w+y.s;
}

int dp[M];

signed main() {

    n=read();
    for(int i=1;i<=n;i++) {
        a[i]=(node){read(), read(), read()};
    }

    sort(a+1, a+n+1, cmp);

    int ans=0;
    for(int i=1;i<=n;i++) {
        for(int j=a[i].s;j>=0;j--) {
            dp[j+a[i].w]=max(dp[j+a[i].w], dp[j]+a[i].v);
            ans=max(ans, dp[j+a[i].w]);
        }
    }

    write(ans);

    return 0;
}
posted @ 2023-10-29 09:21  Trmp  阅读(7)  评论(0编辑  收藏  举报
-->