「 CODE[VS] P2853 」 方格游戏

题目大意

给定一张 $n imes n$ 的网格。每个格子上都有一个系数 $a$,先下 $A$ 和 $B$ 两人选择两条 $(1,1) ightarrow (n,n)$ 路径。要求着两条路径不能相同。并且要计算出两条路径每一个相对应的格子上的系数的差的绝对值之和。

要求选择路径是满足下列条件:

只能选择坐标增加的方向。

解题思路

棋盘 DP。

既然是在一个棋盘中。并且已经规定了行走的方向。所以在移动的格子的数量相同时。两个路径停留的点到 $(1,1)$ 这个点的曼哈顿距离(横坐标$+$纵坐标)是相同的。而且知道了横坐标和曼哈顿距离就可以求出点的纵坐标。

设 $DP[i][j][k]$ 表示两条路径停留点的横坐标分别是 $i$ 和 $j$,距离 $(1,1)$ 这个点的曼哈顿距离是 $k$。

我们考虑枚举曼哈顿距离和两条路径所停留点的横坐标。这样通过横坐标和曼哈顿距离就可以求出纵坐标。如题所说,每一个点只能被他上面或者左边的点到达,所以能够得到下面的方程

$$dp[i][j][k] = max{dp[i][j-1][k-1],dp[i-1][j][k-1],dp[i][j][k-1],dp[i-1][j-1][k-1]}+abs(a[i][k-i]-a[j][k-j])$$

附上代码

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int INF = 2147483640;
int n, a[103][103], dp[103][103][203];
inline int ABS(int a) {
    return a>0 ? a : -a;
}
inline int MAX(int x, int y) {
    return x>y ? x : y;
}
int main() {
    scanf("%d", &n);
    for(int i=1; i<=n; i++)
        for(int j=1; j<=n; j++)
            scanf("%d", &a[i][j]);
    dp[1][1][2] = 0;
    for(int k=3; k<=2*n; k++) {
        for(int j=1; j<=n; j++) {
            for(int i=1; i<=n; i++) {
                if(k-i > n || k-j > n) continue;
                if(k-i < 1 || k-j < 1) break;
                else dp[i][j][k] = MAX(MAX(dp[i-1][j][k-1], dp[i][j-1][k-1]), MAX(dp[i][j][k-1], dp[i-1][j-1][k-1])) + ABS(a[i][k-i]-a[j][k-j]);
            }
        }
    }
    printf("%d", dp[n][n][2*n]);
}
原文地址:https://www.cnblogs.com/bljfy/p/9579346.html