zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    关于java集合框架(二):List
    仪式感
    java的foreach(增强for循环)
    关于Java集合框架(一):概述与Set
    重新开始
    简单fork循环分析
    fork,写时复制(copy-on-write),vfork
    树莓派换源
    Windows下TexLive2018环境配置及检测
    Linux下高精度时间
  • 原文地址:https://www.cnblogs.com/kedebug/p/3006515.html
Copyright © 2011-2022 走看看