多维dp

P1006 传纸条 我的第一道多维dp

我第一眼看到这道题 就知道不会 因为从来没见过 

后来看了神仙的题解 恍然大悟 然而自己写的时候还是有bug(逃

这里给出一个三维数组的解法(oi爷太强了

首先,要找来回两条路径,这样考虑太麻烦,把它转化为两个人从1,1这点一起走,一直走到n,m这点所经过的路径。

定义dp[p][i][j]表示当前走了p步,第一个人走到第i行,第二个人走到第j行的最大价值。

显然两个人的坐标都可以计算出来,第一个人是(i,p-i+1),第二个人是(j,p-j+1).

那么状态转移方程呼之欲出 就是

dp[p][i][j]=max(dp[p-1][i][j],dp[p-1][i-1][j],dp[p-1][i-1][j-1],dp[p-1][i][j-1])+num[i][p-i+1]+num[j][p-j+1];

不要以为到这就结束了!

在循环时 我们一定要判断!!

判断什么呢 当i=j时 代表他们坐标重复了(想想为什么   所以这时候 价值只能算i j其中一个的

还有一点! 循环时 双层循环全部要到m 而不是一个n一个m  因为这里的 i j 全部代表层数 

还有一点(我wa掉的一点   就是双层for不仅要判断层数小于m 而且要判断当前步数小于总步数

要不然会wa掉第二个点(逃

接下来 放代码

#define rep(i,a,b) for(int i=a;i<=b;i++)
#include <stdio.h>
#include <iostream>
using namespace std;
const int e=55;
int dp[2*e][e][e],num[e][e];
int n,m;
int maxx(int a,int b,int c,int d)
{
	if(a<b)
		a=b;
	if(c>a)
		a=c;
	if(d>a)
		a=d;
	return a;
}
int main(int argc, char const *argv[])
{
	cin >> m >> n;
	rep(i,1,m){
		rep(j,1,n){
			cin >> num[i][j];
		}
	}
	dp[1][1][1]=num[1][1];
	rep(p,2,n+m-1){
		for(int i=1;i<=m&&i<=p;i++){
			for(int j=1;j<=m&&j<=p;j++){
				dp[p][i][j]=maxx(dp[p-1][i][j],dp[p-1][i-1][j-1],dp[p-1][i][j-1],dp[p-1][i-1][j]);
				int sum;
				if(i==j)
					sum=num[j][p-j+1];
				else
					sum=num[i][p-i+1]+num[j][p-j+1];
				dp[p][i][j]+=sum;
			}
		}
	}
	printf("%d
", dp[n+m-1][m][m]);
	return 0;
}

  

 

人十我百 人百我万
原文地址:https://www.cnblogs.com/bestcoder-Yurnero/p/10719065.html