「Bzoj 1649」「Usaco2006 Dec」Cow Roller Coaster (背包DP)

BZOJ 1649
Luogu 2854
from: USACO 2006 Dec Sliver(USACO刷题第10题)

显然是二维费用01背包。
但是直接做会超时,而且还有连接的限制。
根据题意可以知道只有在$wi[i]+xi[i]=j$才需要考虑转移
那么我们设$f[i][j]$为铺到$i$,成本为$j$的最大有趣值
那么有下列转移方程
$$f[xi[i]+wi[i]][j] = max(f[xi[i]+wi[i]][j], f[xi[i]][j-ci[i]]+fi[i])$$
同时,这样使用会有后效性,我们将数组按照$xi$排序,接下来按照这个顺序的f[xi[i]]一定是更新完毕的状态,使得无后效性
注意,方程初始化全部为$-INF$,除了$f[0][0]=0$,因为从$f[0][0]$转移的状态才是可行的,否则可能会有轨道不连接的问题

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
#include<vector>
#define ms(i, j) memset(i, j, sizeof i)
#define LL long long
using namespace std;

const int MAXN = 10000 + 5, MAXL = 1000 + 5;

struct data {
    int xi, wi, fi, ci;
    bool operator < (const data &b) const {
        return xi < b.xi;
    }
}di[MAXN];
int L, n, B;
LL f[MAXL][MAXL];//设f[i][j]为铺到i,成本为j 

void clear() {
    ms(f, -127); 
    f[0][0] = 0;
}
void init() {
    clear();
    for (int i=1;i<=n;i++) {
        scanf("%d%d%d%d", &di[i].xi, &di[i].wi, &di[i].fi, &di[i].ci);
    }
    sort(di+1, di+1+n);
}
void solve() {
    LL ans = 0;
    for (int i=1;i<=n;i++) {
        for (int j=B;j>=di[i].ci;j--) {
            f[di[i].xi+di[i].wi][j] = max(f[di[i].xi+di[i].wi][j], f[di[i].xi][j-di[i].ci]+di[i].fi);
            ans = max(ans, f[L][j]);
        }
    }
    if (ans>0) printf("%lld\n", ans); else printf("-1\n");
}
int main() {
    #ifndef ONLINE_JUDGE
    freopen("1.in", "r", stdin);freopen("1.out", "w", stdout);
    #endif
    while (scanf("%d%d%d", &L, &n, &B)==3) init(), solve();
    return 0;
}
------ 本文结束 ------