1. 程式人生 > >「 CODE[VS] P2853 」 方格遊戲

「 CODE[VS] P2853 」 方格遊戲

for lse span i++ pre 棋盤 main name return

題目大意

給定一張 $n\times n$ 的網格。每個格子上都有一個系數 $a$,先下 $A$ 和 $B$ 兩人選擇兩條 $(1,1)\rightarrow (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]); }

「 CODE[VS] P2853 」 方格遊戲