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;
}
原文地址:https://www.cnblogs.com/AWhiteWall/p/12420704.html