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 }

 

你可能感兴趣的:(OS)