HNACM(六)--第四题 探寻宝藏

题目描述

传说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)
所有数据都是整数。 数据之间有一个空格。

样例

标准输入 标准输出
2
2 3
0 10 10
10 10 80
3 3
0 3 9
2 8 5
5 7 100
120
134

双向dp问题
思路:

从左上走到右下↘,再从右下走到左上↖,可以看做从左上向右下走两条路↘↘(不相交的路)使得这两条路径上的值加起来最大。
用一个三维的数组来记录,dp[b][x1][x2],b表示走的步数,表示两条路径上的某个点的横纵坐标相加之和,x1表示第一条路的某一点的横坐标,y1表示第一条路的某一点的横坐标;x2表示第二条路的某一点的横坐标,y2表示第二条路的某一点的横坐标。存在x1+y1=x2+y2=b(2<=b<=r+c)。
只要x1,x2,y1,y2不越界且,y1!=y2就可以保证两条路径无重复点。这两条路径都是从左上走到右下,且只能向下走或者向右走。那么dp[b][x1][x2]=max(dp[b-1][x1][x2](后退一步时,第一条路和第二条路都是从上面走来的),
dp[b-1][x1-1][x2-1](后退一步时,第一条路和第二条路都是从左面走来的),
dp[b-1][x1-1][x2](后退一步时,第一条路是从左面走来,第二条路都是从上面走来的),
dp[b-1][x1][x2-1](后退一步时,第一条路是上面走来,第二条路都是从左面走来的),)+num[x1][y1]+num[x2][y2](这两个千万不能忘);
最后,当走终点右下角的时候选择一个较大的路径max(dp[r+c-1][r][r-1],dp[r+c-1][r-1][r])+num[r][c];记得到所求结果,上述两个题目左上和右下角都为0所以就没有加,直接输出了。

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int M = 55;
int map[M][M], m, n, dp[2*M][M][M];
int DP()
{
    if(m == 1 || n == 1)
    {
        return 0;
    }
    int i, j, k;
    memset(dp, 0, sizeof(dp));
    for(k = 3; k < m+n; k++)
    {
        for (i = 2; i < k && i <= m; i++)
        {
            if (k-i >= n || k-i < 1)    continue;
            for (j = 1; j < k-1 && j <= m-1; j++)
            {
                if (i == j)     continue;
                if (k - j > n || k-j <= 1)  continue;
                dp[k][i][j] = max(max(dp[k-1][i-1][j], dp[k-1][i-1][j-1])
                                    , max(dp[k-1][i][j-1], dp[k-1][i][j]));  
                dp[k][i][j] += map[i][k-i] + map[j][k-j];
            }
        }
    }
    return dp[m+n-1][m][m-1] + map[m][n];  
}
int main()
{
    //freopen("t4.in", "r", stdin);
    int i, j, k;
    cin >> k;
    while(k--)
    {
        cin >> m >> n;
        memset(map, 0, sizeof(map));
        for (i = 1; i <= m; i++)
        {
            for (j = 1; j <= n; j++)
            {
                scanf("%d", &map[i][j]);
            }
        }
        printf("%d\n",DP());
    }
    return 0;
}

你可能感兴趣的:(HNACM)