POJ 1161 Help Jimmy(逆向思维的DP + 记忆化搜索总结)

题意:

黑书 158 铁球落地。

思路:

1. 出发点题目给了,就是小球的初始位置。目标状态也有了,那就是地面。如果定义转移方程:dp[i][0], dp[i][1] 分别表示第 i 个板子左、右到地面的最小时间;

2. 有了出发点,也有了目标位置,这时候可以利用记忆化搜索。(已知状态,未知值)->(中间状态,更容易求的未知值)->(末状态,已知值);

3. 由于本题的末状态只有一个:地面。所以可以采取逆向思维的方法,把上面的式子倒着推过来,先求离地面最近的,再求我们已知的初始状态;

4. 传统的背包问题是:(已知状态,已知值)->(中间状态)->(末状态,未知值)的一个思路,顺理成章。而本题和前面 UVa 10118 有点类似,

   都是一个逆向的思维在里面,不同点是 UVa 10118 末状态未知,而本题是已知的,所以可以转化过来用递归关系式得到解决.

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

const int MAXN = 1010;
const int INFS = 0x3fffffff;

struct BOARD {
    int x1, x2, h;
    bool operator < (const BOARD& other) const { return h < other.h; }
} board[MAXN];

int dp[MAXN][2];

int workout(int n, int maxh) {
    for (int i = 1; i < n; i++) {
        for (int j = i-1; j >= 0; j--) {
            if (board[i].x1 >= board[j].x1 && board[i].x1 <= board[j].x2) {
                int h = board[i].h - board[j].h;
                if (h > maxh) dp[i][0] = INFS;
                else if (j == 0) dp[i][0] = h;
                else dp[i][0] = min(dp[j][0] + board[i].x1 - board[j].x1, dp[j][1] + board[j].x2 - board[i].x1) + h;
                break;
            }
        }
        for (int j = i-1; j >= 0; j--) {
            if (board[i].x2 >= board[j].x1 && board[i].x2 <= board[j].x2) {
                int h = board[i].h - board[j].h;
                if (h > maxh) dp[i][1] = INFS;
                else if (j == 0) dp[i][1] = h;
                else dp[i][1] = min(dp[j][0] + board[i].x2 - board[j].x1, dp[j][1] + board[j].x2 - board[i].x2) + h;
                break;
            }
        }
    }
    return dp[n-1][1];
}

int main() {
    int cases;
    scanf("%d", &cases);
    while (cases--) {
        int n, x, y, maxh;
        scanf("%d%d%d%d", &n, &x, &y, &maxh);
        for (int i = 1; i <= n; i++) {
            scanf("%d%d%d", &board[i].x1, &board[i].x2, &board[i].h);
            if (board[i].x1 > board[i].x2) 
                swap(board[i].x1, board[i].x2);
        }
        board[0].x1 = board[0].x2 = x, board[0].h = y;
        board[n+1].x1 = -20010, board[n+1].x2 = 20010, board[n+1].h = 0;
        n += 2;
        sort(board, board + n);
        printf("%d\n", workout(n, maxh));
    }
    return 0;
}
原文地址:https://www.cnblogs.com/kedebug/p/3006515.html