Vijos 1493 传纸条(DP)

题目链接

第一个多进程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 }

 

posted @ 2012-08-01 19:09  Naix_x  阅读(307)  评论(0编辑  收藏  举报