第一个多进程DP,在Vijos做的第一个题是三取方格数。。。然后发现,这种DP,没见过。。。然后最搞笑的是,做CF的时候,E题神似那种问题,后悔没认真学一下,然后从基础学起,看了个讲多进程的博客,搞一下这个题。。。
先是O(n^4)的暴力解法。这个题n m都是小于50的。所以暴力的方法也过了。
o[i][j][k][u] 代表第一个人到达i,j第二个人到达k,u的取得最大值,其实我一直很疑惑的一个问题是,如何判断不能重复的走的方法,看博客上的处理,原来如此啊。只需要简单的特判一下 i ==k&&j == u如果为真的话,则max+p[i][j]就行了,假的话要max+p[i][j]+p[k][u];max 从4种以前的状态中得到最大值。
1 #include <stdio.h> 2 #include <string.h> 3 int p[51][51],o[51][51][51][51]; 4 int getmax(int a,int b,int c,int d) 5 { 6 int max = -1; 7 if(max < a) 8 max = a; 9 if(max < b) 10 max = b; 11 if(max < c) 12 max = c; 13 if(max < d) 14 max = d; 15 return max; 16 } 17 int main() 18 { 19 int i,j,k,u,n,m,max; 20 scanf("%d%d",&n,&m); 21 for(i = 1;i <= n;i ++) 22 { 23 for(j = 1;j <= m;j ++) 24 scanf("%d",&p[i][j]); 25 } 26 for(i = 1;i <= n;i ++) 27 { 28 for(j = 1;j <= m;j ++) 29 { 30 for(k = 1;k <= n;k ++) 31 { 32 for(u = 1;u <= m;u ++) 33 { 34 max = getmax(o[i-1][j][k-1][u],o[i][j-1][k-1][u],o[i-1][j][k][u-1],o[i][j-1][k][u-1]); 35 if(i == k&&j == u) 36 o[i][j][k][u] = max + p[i][j]; 37 else 38 o[i][j][k][u] = max + p[i][j]+p[k][u]; 39 } 40 } 41 } 42 } 43 printf("%d\n",o[n][m][n][m]); 44 return 0; 45 }
还有一种很神奇的方法,算是压缩状态吧。讲O(n^4)转化为O(n^3),CF那个题,做出来的很多都是用的这种方法。从左上角,每走一步,算一层,可以发现每一层就是都在一条对角线上,也就是他们的和是相等的,所以位置就可以转化为k层和x坐标,因为两个点具有相同的k所以,状态转移方程就可以写成3维的。
o[k][i][j] = max(o[k-1][i-1][j],o[k-1][i][j-1],o[k-1][i-1][j-1],o[i][j])+p[i][k+2-i] + p[j][k+2-i] (以(2,1)为第一层。)这样写0ms,暴力一点的300ms+。
注意各种边界问题,虽然在Vijos可以水过,一定要注意边界问题,没有好的实现方法,观摩CF中大神的实现方法,好简洁。。。
1 #include <stdio.h> 2 #include <string.h> 3 int p[51][51],o[121][51][51]; 4 int getmax(int a,int b,int c,int d) 5 { 6 int max = -1; 7 if(max < a) 8 max = a; 9 if(max < b) 10 max = b; 11 if(max < c) 12 max = c; 13 if(max < d) 14 max = d; 15 return max; 16 } 17 int main() 18 { 19 int i,j,k,n,m,max; 20 scanf("%d%d",&n,&m); 21 for(i = 1;i <= n;i ++) 22 { 23 for(j = 1;j <= m;j ++) 24 scanf("%d",&p[i][j]); 25 } 26 o[0][1][1] = p[1][1]; 27 for(k = 1;k <= n+m-2;k ++) 28 { 29 for(i = 1;i <= k+1&&i <= n;i ++)if(k+2-i<=m)//边界 30 { 31 for(j = 1;j <= k+1&&j <= n;j ++)if(k+2-j<=m)//边界 32 { 33 max = getmax(o[k-1][i][j],o[k-1][i][j-1],o[k-1][i-1][j],o[k-1][i-1][j-1]); 34 if(i == j) 35 o[k][i][j] = max + p[i][k+2-i]; 36 else 37 o[k][i][j] = max + p[i][k+2-i] + p[j][k+2-j]; 38 } 39 } 40 } 41 printf("%d\n",o[n+m-2][n][n]); 42 return 0; 43 }