• P1004 方格取数


    题目

    \(\text{Link.}\)

    解法

    首先不难想到 \(\mathcal O(n^4)\) 的做法:令 \(dp_{x_1,y_1,x_2,y_2}\) 为两个人 同时 走,某时刻分别到达 \((x_1,y_1),(x_2,y_2)\) 的最大收益。需要特判在同一个点的情况。

    不过这个状态实际是冗余的,两人的总步数相等,如果我们知道了其中一人的坐标,就相当于知道了总步数,此时只需要知道另一个人的横/纵坐标就可以得到他的坐标。

    现在我们枚举总步数 \(l\),令 \(dp_{i,j}\) 为第一个人的横坐标为 \(i\),另一个人的横坐标为 \(j\) 时最大收益。这样两人的坐标分别是:\((i,l-i),(j,l-j)\)。转移有

    \[dp_{i,j}=\max\{dp_{i,j},dp_{i-1,j},dp_{i,j-1},dp_{i-1,j-1}\} \]

    这就变成了 \(\mathcal O(n^3)\) 的。

    代码

    #include <cstdio>
    #include <iostream>
    using namespace std;
    
    int dp[150][150], n, w[150][150];
    
    int read() {
        int x = 0, f = 1; char s;
        while((s = getchar()) < '0' || s > '9') if(s == '-') f = -1;
        while(s >= '0' && s <= '9') {x = (x << 1) + (x << 3) + (s ^ 48); s = getchar();}
        return x * f;
    
    }
    
    int main() {
        int a, b, c;
        n = read();
        while(a = read(), b = read(), c = read(), a) w[a][b] = c;
        for(int l = 2; l <= (n << 1); ++ l)
            for(int i = l - 1; i >= 1; -- i)
                for(int k = l - 1; k >= 1; -- k) {
                    int j = l - i, u = l - k;
                    dp[i][k] = w[k][u] + max(dp[i - 1][k - 1], max(dp[i - 1][k], max(dp[i][k], dp[i][k - 1])));
                    dp[i][k] += (i != k) * w[i][j];
                }
        printf("%d\n", dp[n][n]);
        return 0;
    }
    
  • 相关阅读:
    linux 查看安装软件位置(持续跟新)
    POJ 3661 Running (DP思想)
    stringstream的用法
    关于实验室搬家
    POJ 搜索(2)
    Treap的插入删除实现
    碰到一道不错的扩展欧几里德题目 whu 1338
    SRM 144
    关于无向图双连通问题
    POJ 动态规划(2)
  • 原文地址:https://www.cnblogs.com/AWhiteWall/p/12420704.html
Copyright © 2020-2023  润新知