[二维DP] 洛谷P1156 垃圾陷阱 (状态的定义和转移条件问题)

题目

LP1156

思路

首先注意此处的输入数据处理问题,我们以下的推理都是建立在垃圾按扔入时间t排序好的,所以一定要对输入数据进行处理。


本题显然是个多阶段决策类的问题,那么难点就在于状态的定义。本题的题解的状态定义是多样化的,有用一维就做出来的大佬,普遍是两维数组。但两维的(i,j),大多都是i为垃圾序号,j为所处高度,d为最大生存时间。我用的是少见的一种,i为垃圾序号,j为生存时间,d为最大高度。
由此可得,部分灵活的DP题状态定义是多样化的,找到适合自己的一种即可。


1.状态定义:d(i,j),当遍历到第i个垃圾时,当生存时间为j时,最大到达高度。
2.状态的转移:
(1).d(i,j) = d(i-1,j)+h(i),即将这个垃圾垫起来,条件是j>t(i)
(2).d(i,j) = d(i-1, j-f(i)),即将这个垃圾吃掉,条件是j-f(i) > t(i)
(即吃的时候还没死)


对于这种什么都可以拿来做状态的题,状态关系一般也比较复杂,但是状态转移方程很难错,但是特别应该注意状态转移条件,哦我知道你已经在考虑了,但是你考虑的是(j-f(i) > 0防止负下标)而不是(j-f(i) > t(i))。。。
反正就应该很注意一些,因为这种题,你说你状态转移条件错了,发生的答案只是数值上的偏移,有时候样例规模小根本发现不了。即使noip这种类型的,心好给你个大样例,数值只是偏移没有不正常,很难debug的。所以应该特别小心此类的错误。

代码

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#define _for(i,a,b) for(int i = (a); i<(b); i++)
#define _rep(i,a,b) for(int i = (a); i<=(b); i++)
using namespace std;

const int INF = 1000000;
const int maxg = 100 + 5;
const int maxt = 4000 + 5;
int dd, n, d[maxg][maxt];  // d[gg][tt]:遍历到第gg个垃圾,奶牛可以活到tt时间,的最高高度

struct gar {
    int t, f, h;
    bool operator < (const struct gar& rhs) const {
        return t < rhs.t;
    }
}gars[maxg];
// dd:井深度,n:垃圾总数,t:垃圾i投入的时间,f:垃圾i增长生命时间,h:垃圾i可以堆的高度

int main() {
    scanf("%d%d", &dd, &n);
    _rep(i, 1, n) scanf("%d%d%d", &gars[i].t, &gars[i].f, &gars[i].h);
    sort(gars + 1, gars + 1 + n);

    // 初始状态
    _rep(i, 0, maxt) d[0][i] = -INF;
    d[0][10] = 0;

    _rep(gg, 1, n)
        _rep(tt, 0, maxt-1) {  // 此处不能使用maxt作为循环终止量
            d[gg][tt] = -INF;
            if (tt >= gars[gg].t) {  // 这次能活下来
                if (tt - gars[gg].f >= 0 && tt - gars[gg].f >= gars[gg].t)
                    d[gg][tt] = max(d[gg][tt], d[gg - 1][tt - gars[gg].f]);
                if (tt >= gars[gg-1].t)
                    d[gg][tt] = max(d[gg][tt], d[gg - 1][tt] + gars[gg].h);
            }
        }

    int gg, maxd = 0;
    bool found = false;
    for (gg = 0; gg <= n && !found; gg++) {
        _rep(tt, 0, maxt-1) { // 此处不能使用maxt作为循环终止量
            if (d[gg][tt] >= 0) maxd = max(maxd, tt);
            if (d[gg][tt] >= dd) {
                found = true;
                break;
            }
        }
    }

    if (found) printf("%d\n", gars[gg-1].t);
    else printf("%d\n", maxd);

    return 0;
}

猜你喜欢

转载自blog.csdn.net/icecab/article/details/81070315