题目见洛谷:https://www.luogu.org/problem/show?pid=1004
一个人走两遍,从左上到右下,可以看做是两个人同时从左上到右下,动态规划可以理解为有策略的递推,递推则是从已知推向未知。从题意中可以知道,当如果只有1*1时是已知的,当站在某个(x,y)格子里时,它的最优值是来自于左边或者上边的最大值+(x,y)点上的数。那么当有两个人同时从左上到右下时,则有四种情况:
1. 上 , 上
2. 上 , 左
3. 左 , 上
4. 左 , 左
因此需要在这四种情况中最大的+ 这俩人所站的当前位置上的两个数。特殊的,当两个人走到了同一个格子里时,因为当一个人取走后便为0了,因此只加一次。所以可以用四维数组记录两个人走到对应格子里时的最优值,dp[i][j][x][y]代表一个人站在(i,j)格子里,另一个人站在(x,y)格子里时的最优值,动态规划转移方程是:假设第一个人站在(i,j)格子,第二个人站在(x, y)格子里。那么动态规划转移方程为:
当俩人未站在同一个点时:
dp[i][j][x][y]=map[x][y]+map[i][j]+max(max(dp[i][j-1][x-1][y],dp[i-1][j][x][y-1]),max(dp[i-1][j][x-1][y],dp[i][j-1][x][y-1]));
其中{1<= i,j,x,y <=n;}
当俩人走到了同一个格子里时:
dp[i][j][x][y] = map[i][j]+max(max(dp[i][j-1][x-1][y],dp[i-1][j][x][y-1]),max(dp[i-1][j][x-1][y],dp[i][j-1][x][y-1]));其中{1<= i,j,x,y <=n;}
代码如下:
#include<iostream>
#include<algorithm>
using namespace std;
int dp[10][10][10][10],map[10][10];
int main(){
int n;
cin >> n;
while(1){
int x,y,num;
cin >> x >> y >> num;
if(x ==0 && y==0 && num==0)
break;
map[x][y] = num;
}
dp[1][1][1][1] = map[1][1];
for(int i = 1; i<= n; i++)
for(int j = 1; j<= n; j++)
for(int x = 1; x<= n; x ++)
for(int y = 1; y <= n; y++){
if(i == x && j == y){
dp[i][j][x][y] = map[i][j]+max(max(dp[i][j-1][x-1][y],dp[i-1][j][x][y-1]),max(dp[i-1][j][x-1][y],dp[i][j-1][x][y-1]));
}
else{
dp[i][j][x][y] = map[x][y]+map[i][j]+max(max(dp[i][j-1][x-1][y],dp[i-1][j][x][y-1]),max(dp[i-1][j][x-1][y],dp[i][j-1][x][y-1]));
}
}
cout << dp[n][n][n][n] << endl;
return 0;
}
由于在方格中取数第k次取数所站的格子一定满足 行号+ 列号 = k+1,那么当知道俩人所在的格子行号的情况下,根据k便可算的对应的列号。因此我们可以将上面的动态规划转变成三维,减少空间复杂度。
具体代码见:
#include<iostream>
#include<algorithm>
using namespace std;
int dp[21][10][10],map[10][10];
int main()
{
int n;
cin >> n;
while(1)
{
int x,y,num;
cin >> x >> y >> num;
if(x ==0 && y==0 && num==0)
break;
map[x][y] = num;
}
dp[1][1][1] = map[1][1];
for(int k= 2; k<= 2*n-1 ;k++)
for(int i = 1; i<= n; i++)
for(int x = 1; x<= n; x++)
{
int j= k+1-i,y = k+1 - x;
if(i == x )
{
dp[k][i][x] = map[i][j]+max(max(dp[k-1][i-1][x-1],dp[k-1][i][x]),max(dp[k-1][i-1][x],dp[k-1][i][x-1]));
}
else
{
dp[k][i][x] = map[x][y]+map[i][j]+max(max(dp[k-1][i-1][x-1],dp[k-1][i][x]),max(dp[k-1][i-1][x],dp[k-1][i][x-1]));
}
}
cout << dp[2*n-1][n][n] << endl;
return 0;
}