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;
    }
  • 相关阅读:
    C#事件(event)解析
    dll加入到GAC后,如何方便的调试
    『C程序设计』读书笔记系列文章之第四章 逻辑运算和判断选取控制
    C#委托之个人理解
    虚方法(virtual)和抽象方法(abstract)的区别
    『C程序设计』读书笔记系列文章之第二章 数据类型、运算符与表达式
    SOA概览(转)
    今天学的几个有用的句型
    【老孙随笔】PPT高手的启示
    【项目经理之修炼(11)】《初级篇》什么样的项目经理才可能成功??
  • 原文地址:https://www.cnblogs.com/kedebug/p/3006515.html
Copyright © 2011-2022 走看看