三取方格数
描述
设有N*N的方格图,我们将其中的某些方格填入正整数,而其他的方格中放入0。某人从图得左上角出发,可以向下走,也可以向右走,直到到达右下角。在走过的路上,他取走了方格中的数。(取走后方格中数字变为0)此人从左上角到右下角共走3次,试找出3条路径,使得取得的数总和最大。
格式
输入格式
第一行:N (4<=N<=20)
接下来一个N*N的矩阵,矩阵中每个元素不超过80,不小于0
输出格式
一行,表示最大的总和。
限制
各个测试点1s
提示
多进程DP
f[step][x1][x2][x3]表示当走到第step步时,三个点分别取x1,x2,x3时的最优解。
由于只能向下或向右移动,所以当移动步数一定时,所能移动到的格子是一个 / 的对角线,所以枚举三次移动到的横坐标,可以O(1)第算出纵坐标,注意每个方格只能取一次。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<cmath> 6 #include<algorithm> 7 using namespace std; 8 const int maxn=25; 9 int f[maxn*2][maxn][maxn][maxn]; 10 int map[maxn][maxn]; 11 int N; 12 int main(){ 13 14 scanf("%d",&N); 15 for(int i=1;i<=N;i++){ 16 for(int j=1;j<=N;j++){ 17 scanf("%d",&map[i][j]); 18 } 19 } 20 f[1][1][1][1]=map[1][1]; 21 for(int step=2;step<=2*N-1;step++){//枚举步数,假定走到 (1,1) 用了一步 22 for(int x1=max(1,step-N+1);x1<=min(N,step);x1++){//x1,x2,x3 是用 step步走到横坐标为 x1,x2,x3的方格, 23 for(int x2=max(1,step-N+1);x2<=min(N,step);x2++){//用min(),max()都是保证方格不越界的方式 24 for(int x3=max(1,step-N+1);x3<=min(N,step);x3++){ 25 int delta=map[x1][step-x1+1]+map[x2][step-x2+1]+map[x3][step-x3+1]; 26 if(x1==x2) delta-=map[x1][step-x1+1]; 27 if(x1==x3) delta-=map[x1][step-x1+1]; 28 if(x2==x3) delta-=map[x2][step-x2+1]; 29 if(x1==x2&&x1==x3) delta+=map[x1][step-x1+1];//多减去了一次 30 31 f[step][x1][x2][x3]=max(f[step-1][x1][x2][x3],max(f[step-1][x1-1][x2][x3], 32 max(f[step-1][x1][x2-1][x3],max(f[step-1][x1][x2][x3-1], 33 max(f[step-1][x1-1][x2-1][x3],max(f[step-1][x1-1][x2][x3-1], 34 max(f[step-1][x1][x2-1][x3-1],f[step-1][x1-1][x2-1][x3-1])))))))+delta; 35 36 37 } 38 } 39 } 40 } 41 cout<<f[2*N-1][N][N][N]; 42 return 0; 43 }