nyoj 61 传纸条

Nyoj 61 传纸条

前几天无意中看到多进程DP,原来我苦恼很长时间的传纸条问题竟然是双进程DP,搜了几篇大牛的关于双进程DP的文章,有些思路了:

拿传纸条问题来说吧,其实就是找两条从左上角到右下角不相交的路径(除了头和尾),使路径上的和最大。因为路径不能相交,所以我们必须同时考虑两个人的位置,若两人的位置设为x1,y1, x2,y2,状态转移方程可以写成如下形式:

f(x1,y1,x2,y2)=max{f(x1-1,y1,x2-1,y2),f(x1-1,y1,x2,y2-1),f(x1,y1-1,x2-1,y2),f(x1,y1-1,x2,y2-1)}+map[x1][y1]+map[x2][y2] ;(其中x1 !=x2 || y1 !=y2)

可见一般的做法不管是时间复杂度还是空间复杂度都很高,得优化。

因为两人都必须向右或向下走,所以一定会有 x1+y1==x2+y2 ; 那我们设 x1+y1=k ; x2+y2=k ; 我们可以把状态 f(x1,y1,x2,y2) 转化为 f(k,x1,x2) 因此就会减少一维。状态转移方程可以写成如下形式:

f(k,x1,x2)=max{f(k-1,x1-1,x2),f(k-1,x1,x2-1),f(k-1,x1,x2),f(k-1,x1-1,x2-1)}+map[x1][k-x1]+map[x2][k-x2] ;(x1 != x2)(想想四种状态如何来的呢?)

 

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int map[101][101],res[201][101][101];
int max(int a,int b,int c,int d)
{
int s,t;
s = a > b ? a : b;
t = c > d ? c : d;
return s > t ? s : t;
}
int work(int n,int m)
{
int k,x1,x2,y1,y2;
res[2][1][1]=map[1][1];
for(k=2;k<=n+m;k++)
for(x1=1;x1<=n;x1++)
for(x2=1;x2<=n;x2++)
{
y1 = k - x1; y2 = k - x2;
if(y1 < 0 || y2 < 0 || y1 > m || y2 > m || y1 == y2)
continue;
res[k][x1][x2]=max(res[k-1][x1-1][x2],res[k-1][x1][x2-1],res[k-1][x1-1][x2-1],res[k-1][x1][x2])+map[x1][y1]+map[x2][y2];
}
return res[m+n-1][n][n-1]+map[n][m];
}
int main()
{
int i,j,k,m,n;
scanf("%d",&n);
while(n--)
{
memset(res,0,sizeof(res));
scanf("%d %d",&m,&k);
for(i=1;i<=m;i++)
for(j=1;j<=k;j++)
scanf("%d",&map[i][j]);
printf("%d\n",work(m,k));
}
return 0;
}

你可能感兴趣的:(OJ)