您的位置:首页 > 其它

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种以前的状态中得到最大值。

#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: