Vijos 1493 传纸条(DP)
2012-08-01 19:09
197 查看
题目链接
第一个多进程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种以前的状态中得到最大值。
还有一种很神奇的方法,算是压缩状态吧。讲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中大神的实现方法,好简洁。。。
第一个多进程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种以前的状态中得到最大值。
#include <stdio.h> #include <string.h> int p[51][51],o[51][51][51][51]; int getmax(int a,int b,int c,int d) { int max = -1; if(max < a) max = a; if(max < b) max = b; if(max < c) max = c; if(max < d) max = d; return max; } int main() { int i,j,k,u,n,m,max; scanf("%d%d",&n,&m); for(i = 1;i <= n;i ++) { for(j = 1;j <= m;j ++) scanf("%d",&p[i][j]); } for(i = 1;i <= n;i ++) { for(j = 1;j <= m;j ++) { for(k = 1;k <= n;k ++) { for(u = 1;u <= m;u ++) { 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]); if(i == k&&j == u) o[i][j][k][u] = max + p[i][j]; else o[i][j][k][u] = max + p[i][j]+p[k][u]; } } } } printf("%d\n",o [m] [m]); return 0; }
还有一种很神奇的方法,算是压缩状态吧。讲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中大神的实现方法,好简洁。。。
#include <stdio.h> #include <string.h> int p[51][51],o[121][51][51]; int getmax(int a,int b,int c,int d) { int max = -1; if(max < a) max = a; if(max < b) max = b; if(max < c) max = c; if(max < d) max = d; return max; } int main() { int i,j,k,n,m,max; scanf("%d%d",&n,&m); for(i = 1;i <= n;i ++) { for(j = 1;j <= m;j ++) scanf("%d",&p[i][j]); } o[0][1][1] = p[1][1]; for(k = 1;k <= n+m-2;k ++) { for(i = 1;i <= k+1&&i <= n;i ++)if(k+2-i<=m)//边界 { for(j = 1;j <= k+1&&j <= n;j ++)if(k+2-j<=m)//边界 { 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]); if(i == j) o[k][i][j] = max + p[i][k+2-i]; else o[k][i][j] = max + p[i][k+2-i] + p[j][k+2-j]; } } } printf("%d\n",o[n+m-2] ); return 0; }
相关文章推荐
- vijos 1493 双线程DP
- Vijos 1493 传纸条
- VIJOS 1493 传纸条
- Vijos P1493 传纸条 (双线程DP)
- Vijos P1493 传纸条(动态规划,双线程DP)
- Vijos P1493 传纸条 双线程DP
- [NOIP2013][vijos1850]小朋友的数字(dp+贪心)
- vijos[P1054] luogu[P2662] 牛场围栏 (数论+最短路,(DP可水过))
- 传纸条 NOIP2008 洛谷1006 二维dp
- codevs1169 传纸条(棋盘dp)
- Vijos 1286 座位安排(状态压缩DP)
- DP - 传纸条
- NYOJ 61 传纸条 && NYOJ 712 探寻宝藏 -- 双线dp
- vijos P1412多人背包 DP的前k优解
- codevs1169传纸条 不相交路径取最大,四维转三维DP
- ♥Vijos 1242-邮局问题【经典DP】
- NYOJ 61传纸条(一) 双线程DP问题
- nyoj 61 传纸条(一)【 双线程 DP】
- Vijos 小白逛公园 线段树加DP
- Vijos 1144 小胖守皇宫 [树形dp]