第六届程序设计 探 寻 宝 藏 (双线程DP)

来源:互联网 发布:防蓝光软件f.lux 编辑:程序博客网 时间:2024/04/27 20:39

探 寻 宝 藏

时间限制:1000 ms  |  内存限制:65535 KB
难度:5
描述

传说HMH大沙漠中有一个M*N迷宫,里面藏有许多宝物。某天,Dr.Kong找到了迷宫的地图,他发现迷宫内处处有宝物,最珍贵的宝物就藏在右下角,迷宫的进出口在左上角。当然,迷宫中的通路不是平坦的,到处都是陷阱。Dr.Kong决定让他的机器人卡多去探险。

但机器人卡多从左上角走到右下角时,只会向下走或者向右走。从右下角往回走到左上角时,只会向上走或者向左走,而且卡多不走回头路。(即:一个点最多经过一次)。当然卡多顺手也拿走沿路的每个宝物。

Dr.Kong希望他的机器人卡多尽量多地带出宝物。请你编写程序,帮助Dr.Kong计算一下,卡多最多能带出多少宝物。
输入
第一行: K 表示有多少组测试数据。
接下来对每组测试数据:
第1行: M N
第2~M+1行: Ai1 Ai2 ……AiN (i=1,…..,m)


【约束条件】
2≤k≤5 1≤M, N≤50 0≤Aij≤100 (i=1,….,M; j=1,…,N)
所有数据都是整数。 数据之间有一个空格。
输出
对于每组测试数据,输出一行:机器人卡多携带出最多价值的宝物数
样例输入
22 30 10 1010 10 803 30 3 92 8 55 7 100
样例输出
120134
来源
第六届河南省程序设计大赛


用四维数组来动态规划解决了这倒题。

设dp[i][j][k][l]为从 (0, 0) 位置由两条不交叉的线路走到 (i, j),(k, l) 位置时的获取的最多宝物,则它的上一步可能有四种情况:

  1. 第一个点由上走来,第二个点也由上走来,此时的获取的宝物为f[i - 1][j][k - 1][l] + a[i][j] + a[k][l]
  2. 第一个点由上走来,第二个点则由左走来,此时的获取的宝物为f[i - 1][j][k][l - 1] + a[i][j] + a[k][l],但此时应考虑第一个点的上方的点是否会与第二个点的左方的点重合,如果重合则不可取
  3. 第一个点由左走来,第二个点则由上走来,此时的获取的宝物为f[i][j - 1][k - 1][l] + a[i][j] + a[k][l],但此时应考虑第一个点的左方的点是否会与第二个点的上方的点重合,如果重合则不可取
  4. 第一个点由左走来,第二个点也由左走来,此时的获取的宝物为f[i][j - 1][k][l - 1] + a[i][j] + a[k][l]

取四种情况中的最大者即可。

这题与NYOJ 61是同类问题,但是,有一点细节要注意,最后终点的值也要算上,上面的动态方程得到的值不包含两个A 和 B的值,因为 A是起点,所以,他的值一般是0,所以,得到最后的结果应该是 int sum = max(dp[m-1][n][m-1][n],dp[m-1][n][m][n-1],dp[m][n-1][m-1][n],dp[m][n-1][m][n-1]) + a[m][n];


#include<cstdio>
#include<algorithm>
#include<string.h>
#include<iostream>
#define max(x,y) (x<y? y: x)
using namespace std;
int a[52][52];
int dp[52][52][52][52];
int main()
{
 int test,m,n;
 scanf("%d",&test);
 while(test--){
  scanf("%d%d",&m,&n);
  for(int i=1;i<=m;i++)
  for(int j=1;j<=n;j++)scanf("%d",&a[i][j]);
  memset(dp,0,sizeof(dp));
  
  for(int i=1;i<=m;i++)
  for(int j=1;j<=n;j++)
  for(int p=i+1;p<=m;p++){
   int q=i+j-p;
   if(q<=0)continue;
   dp[i][j][p][q]=max(max(dp[i-1][j][p-1][q],dp[i][j-1][p][q-1]),max(dp[i-1][j][p][q-1],dp[i][j-1][p-1][q]))+a[i][j]+a[p][q];
  }
  int sum=max(
       max(dp[m-1][n][m-1][n],dp[m-1][n][m][n-1]),
    max(dp[m][n-1][m][n-1],dp[m][n-1][m-1][n]))+a[m][n];
  printf("%d\n",sum);
 }
 return 0;
}


0 0