双程动态规划 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\n", f[m+n-1][n][n-1]); } return 0; }