• HDU4362 Dragon Ball DP+优化


    这题如果采用普通的DP方程的话果断TLE。所以需要对DP方程进行优化。

    由于这里龙珠可以随意选取,所以龙珠的编号也就没有了什么意义了,所以直接先对龙珠进行排序,我们只要保证其位置和花费同步排序就可以了。

    接下来就是优化了,这个部分可以见代码,在上一题中使用的同步滑动指针,这里则不然,需要根据数值来异步滑动指针。

    代码如下:

    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    #define INF 0x7f7f7f7f
    using namespace std;
    
    int N, M, x, dp[55][1005];
    // dp[i][j] 代表第i时刻选择j号物品的最小值 
    struct Node
    {
        int pos, ti;
        bool operator < (Node temp) const
        {
            return pos < temp.pos;    
        }
    }e[55][1005];
    
    // dp[i][j] 表示i时刻拿j个龙珠的最少花费
    // 完整的dp方程是 dp[i][j] = min( dp[i-1][k] - abs(loc[i][j] - loc[i-1][k]) + ti[i][j] )
    // 当 loc[i][j] < loc[i-1][k]
    // 方程变为 dp[i][j] = min( dp[i-1][k] + loc[i][j] - loc[i-1][k] + ti[i][j])
    // 显然此时只要求得 dp[i-1][k] - loc[i-1][k] 的最小值来递推便可了
    // 同理当 loc[i][j] > loc[i-1][k]
    // 方程变为 dp[i][j] = min( dp[i-1][k] - loc[i][j] + loc[i-1][k] + ti[i][j])
    // 显然此时只要求得 dp[i-1][k] + loc[i-1][k] 的最小值来递推便可了
    
    void read()
    {
        for (int i = 1; i <= M; ++i) {
            for (int j = 1; j <= N; ++j) {
                scanf("%d", &e[i][j].pos);
            }
        }
        for (int i = 1; i <= M; ++i) {
            for (int j = 1; j <= N; ++j) {
                scanf("%d", &e[i][j].ti);
            }
            sort(e[i]+1, e[i]+N+1);  // 对所有的坐标进行排序
        }
    }
    
    void DP()
    {
        int Min, k;
        memset(dp, 0x7f, sizeof (dp));
        for (int i = 1; i <= N; ++i) {
            dp[0][i] = 0;
            e[0][i].pos = x;
        }
        for (int i = 1; i <= M; ++i) {
            k = -1;
            Min = INF; // 假设是从该点的左边的递推过来
            // 由于给定的点不一定满足 ptr < j,那么前面的点的坐标一定小于后面的点 
            // 所以要进行一次排序,来使得其满足上述的性质,这样才能够使得dp[i][j]能够取到最优值
            for (int j = 1, ptr = 1; j <= N; ++j) {
                while (ptr <= N && e[i-1][ptr].pos <= e[i][j].pos) {
                    if (Min > dp[i-1][ptr] - e[i-1][ptr].pos) {
                        Min = dp[i-1][ptr] - e[i-1][ptr].pos;
                        k = j;
                    }
                    ++ptr;
                }
                if (k != -1) {
                    dp[i][j] = Min + e[i][j].pos + e[i][j].ti;
                }
            }
            k = -1;
            Min = INF;
            for (int j = N, ptr = N; j >= 1; --j) {
                while (ptr >= 1 && e[i-1][ptr].pos > e[i][j].pos) {
                    if (Min > dp[i-1][ptr] + e[i-1][ptr].pos) { 
                        Min = dp[i-1][ptr] + e[i-1][ptr].pos;
                        k = j;
                    }
                    --ptr;
                }
                if (k != -1) {
                    dp[i][j] = min(dp[i][j], Min - e[i][j].pos + e[i][j].ti);
                }
            }
        }
        Min = INF;
        for (int i = 1; i <= N; ++i) {
            Min = min(Min, dp[M][i]);
        }
        printf("%d\n", Min);
    }
    
    int main()
    {
        int T;
        scanf("%d", &T);
        while (T--) {
            scanf("%d %d %d", &M, &N, &x);
            read();
            DP();
        }
        return 0;
    }
  • 相关阅读:
    CSS实现商城分类导航效果(hover选择器)
    框架设计读书笔记--扩展点设计--组合法
    框架设计读书笔记--扩展点设计--钩子方法
    Ferris教程学习笔记:js示例2.8 求出数组中所有数字的和
    Ferris教程学习笔记:js示例2.7 点击Div,显示其innerHTML
    Ferris教程学习笔记:js示例2.6 百度输入法
    Ferris教程学习笔记:js示例2.5 记住密码提示框
    Ferris教程学习笔记:js示例2.4 鼠标移入改变样式,鼠标移出恢复
    程序最佳的学习方式
    Ferris教程学习笔记:js示例2.3 用循环将三个DIV变成红色
  • 原文地址:https://www.cnblogs.com/Lyush/p/2645008.html
Copyright © 2020-2023  润新知