1. 程式人生 > >codevs 2853 方格遊戲--棋盤dp

codevs 2853 方格遊戲--棋盤dp

abs cstring span tar bsp problem iostream pan stream

方格遊戲:http://codevs.cn/problem/2853/

這和傳紙條和noip方格取數這兩個題有一定的相似性,當第一眼看到的時候我們就會想到設計$dp[i][j][k][l]$(i,j表示一個人走到 i 行 j 個點,而另一個人走到 k 行第l個點)這麽一個狀態。

轉移方程當然是$dp[i][j][k][l] = max{ dp[i-1][j][k-1][l] ,dp[i-1][j][k][l-1] ,dp[i][j-1][k-1][l] ,dp[i][j-1][k][l-1 }$。

這樣設計沒問題,只是空間限制不足,現在我們考慮進行優化。

註意題目中的一個限制條件,只能向右和向下走,那麽每個人每次走到的點到出發點的曼哈頓距離相等。

曼哈頓距離:可以理解為 | 當前點的橫坐標-出發點的橫坐標 | + |當前點的縱坐標-出發點的縱坐標 | 。

有了曼哈頓距離,那麽我們可以由每個點的橫坐標表示出每個點的縱坐標,如此的話,我們設計狀態的時候可以只設計每個人的橫坐標加上曼哈頓距離這一狀態。

那麽這就是一個三維dp[i][j][k](i表示第一個人的橫坐標,j表示的二個人的,k表示曼哈頓距離)。

說到如何繼承無非有四種:

$dp[i][j][k] = max{ dp[i-1][j][k-1] ,dp[i][j-1][k-1] ,dp[i-1][j-1][k-1] ,dp[i][j][k-1] }$

不要忘記加上走到這個點獲得的公平值。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
int n,a[111][111];
int dp[111][111][222];
int max(int a,int b){ return a>b?a:b; }
int abs(int x){ return x<0?-x:x; } 
int main()
{
    scanf("%d",&n);
    
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%d",&a[i][j]); for(int k=1;k<2*n;k++) { for(int i=1;i<=k&&i<=n;i++) { for(int j=1;j<=k&&j<=n;j++) { int s=max(max(dp[i-1][j][k-1],dp[i][j-1][k-1]),max(dp[i-1][j-1][k-1],dp[i][j][k-1])); dp[i][j][k]=s+abs(a[i][k-i+1]-a[j][k-j+1]); } } } printf("%d",dp[n][n][2*n-1]); }

codevs 2853 方格遊戲--棋盤dp