双程动态规划 nyoj61

题目大意:

在矩阵m*n中,从(1,1)点到(m,n)点,再从(m,n)点到(1,1)点,所走路线经过的同学最大好心值, 要求每个点只能走一遍。

分析:

①我们可以把它只看成两个人同时从(1,1)点, 走到(m,n)点。

②因为只可以往两个方向走所以无论什么了路线,从(1,1)到(m,n)所走的步数一定相同。开四维数组存状态的话f[x1][y1][x2][y2]](表示当前一个人走在(x1,y1)一人走在(x2,y2))那么意思也就是x1+y1 = x2+y2。

③此题中开四维数组太大,会超时。又知道同一时间所走的步数相同。那么我们可以设一个三维数组f[i][x1][x2]: i代表第i步(或者i时刻),第一个人在x1行,第二个人在x2行时,所经过的同学最大好心值。 细心地应该发现:一共走的步数已知,向下走的步数(也就是x1, x2)已知,那么向右走的步数也能知道啦 y1= i - x1; y2 = i - x2; 其实f[i][x1][x2]已经暗示了两个人所在的位置(x1, i-x1),(x2, i-x2),所代表的和四维数组f[x1][y1][x2][y2]一样。 

额。。。说了这么多,不知明白没有。好了来代码吧! 还要注意的是:我的数组是从(1,1)开始的。 如果从(0,0)开始只要稍微改一下边界就行。

#include<iostream>
#include<cstdio>
#include<string.h>
#include<math.h>
using namespace std;

int t, m, n, a[100][100], f[150][100][100];
int max1(int a, int b, int c, int d)
{
    a = max(a, b);
    c = max(c, d);
    a = max(a, c);
    return a;
}
void dp()
{
    for(int i = 3; i < m+n; i++)
    {
        for(int x1 = 1; x1 <= n && x1 <= i-1; x1++)
        {
            for(int x2 = 1; x2 < n && x2 < i-1; x2++)
            {
                int y1 = i - x1;
                int y2 = i - x2;
                if(y1 == y2) continue;//如果y1, y2不同那么x1,x2一定也不同。那么两个人就不会走相同的点了
                f[i][x1][x2] = max1(f[i-1][x1][x2], f[i-1][x1][x2-1], f[i-1][x1-1][x2],
                                f[i-1][x1-1][x2-1])+a[x1][y1]+a[x2][y2];
            }
        }
    }
}
int main()
{
    cin >> t;
    while(t--)
    {
        memset(a, 0, sizeof(a));
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= m; j++)
                scanf("%d", &a[i][j]);
        memset(f, 0, sizeof(f));
        dp();
        printf("%d
", f[m+n-1][n][n-1]);
    }
    return 0;
}
View Code

 

原文地址:https://www.cnblogs.com/wd-one/p/4454563.html