探寻宝藏---双向dp

来源:互联网 发布:mac os beta 编辑:程序博客网 时间:2024/05/02 00:00

题目描述

传说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 80
3 30 3 92 8 55 7 100

样例输出

120
134

 

题意很清晰啦,一个机器人从(1,1)点出发到(m,n)点,再从(m,n)点回到最初点。我们可以把它看成在(1,1)点同时有两个机器人出发到(m,n)点。

我开始做的是四维的。f[i][j][x][y]表示 : 机器人一在(i,j),机器人2在(x,y)时所收集的宝藏最多是多少。机器人1从上面(i-1 , j)或者左面(i , j-1)走到(i, j),机器人2从上面(x-1, y)或者左面(x, y-1)走到(x, y). 所以f[i][j][x][y] = max(f[i-1][j][x-1][y],  f[i-1][j][x][y-1],  f[i][j-1][x-1][y],  f[i][j-1][x][y-1]). 上一状态有四种情况。

这需要四层循环,如果矩阵太大的话就容易超啦。不过我们发现有些细节,这样可以减少一部分无用的循环。注意 : 同一时间两个机器人走的步数是一样的,也就是i+j= x+y。

#include<iostream>#include<cstdio>#include<cstring>using namespace std;int e[55][55],dp[55][55][55][55],n,m;int x1[4] = {0,0,1,1}, y1[4] = {1,1,0,0}, x2[4]={0,1,0,1}, y2[4] = {1,0,1,0};void dp1(){int i,j,x,y;for(i=1;i<=n;i++){for(j=1;j<=m;j++){for(x=1;x<=i;x++){for(y=1;y<=m;y++){if(i==x&&j==y) continue;if((i+j)!=(x+y)) continue;for(int k=0;k<4;k++){int sum=e[i][j]+e[x][y];dp[i][j][x][y]=max(dp[i][j][x][y],dp[i-x1[k]][j-y1[k]][x-x2[k]][y-y2[k]]+sum);}}}}}}int main(){int t;scanf("%d",&t);while(t--){scanf("%d%d",&n,&m);memset(dp,0,sizeof(dp));memset(e,0,sizeof(e));for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){scanf("%d",&e[i][j]);}}dp1();printf("%d\n",dp[n][m-1][n-1][m]+e[n][m]);}return 0;}


0 0
原创粉丝点击