题目链接:http://acm.hrbust.edu.cn/index.php?m=ProblemSet&a=showProblem&problem_id=1214
题目大意:可以理解为2个人同时从A点出发,然后同时到达B点,两人可以捡路上的东西(捡一次就没了),让你求解走完之后,所得的最大的值。
问题分析:
1)一开始我才用的战略是:采用两次二维dp,第一次找出最大的路径,走过的置为0,接下来,在第一次状态改变的情况下,再dp一下,找出当前状态的最长路径。最后加和。
事实证明,这样的做法是错的,因为你第一次dp的过程中改变了状态,也就是说第二次受到了第一次dp的影响,这样他们最后得出的结果就不正确。
2)正确的思路:回归动态规划的本源,我们来分析这个问题。
(1)两个人,可以看成是两个大的状态。
(2)每个人都受到两个状态的影响,即左或者上。
(3)那么当前的dp值就是前边2*2种状态中的某个值。
核心代码:
状态方程:dp[i1][j1][i2][j2]=max{dp[i1][j1-1][i2-1][j2],dp[i1-1][j1][i2-1][j2],dp[i1-1][j1][i2][j2-1],dp[i1][j1-1][i2][j2-1]}+a[i1][j1] //(i1==i2&&j1==j2)
dp[i1][j1][i2][j2]=max{dp[i1][j1-1][i2-1][j2],dp[i1-1][j1][i2-1][j2],dp[i1-1][j1][i2][j2-1],dp[i1][j1-1][i2][j2-1]}+a[i1][j1]+a[i2][j2]
代码:
#include <bits/stdc++.h>
using namespace std;
int dp[11][11][11][11];
int a[11][11];
int main()
{
int n;while(~scanf("%d",&n)){
memset(a,0,sizeof(a));
int x,y,val;while(scanf("%d%d%d",&x,&y,&val)){
if(!x&&!y&&!val) break;
a[x][y]=val;
for(int i1=1;i1<=n;i1++)
for(int j1=1;j1<=n;j1++)
for(int i2=1;i2<=n;i2++)
for(int j2=1;j2<=n;j2++){
int tmp= -1e5;
tmp=max(tmp,dp[i1-1][j1][i2-1][j2]);
tmp=max(tmp,dp[i1-1][j1][i2][j2-1]);
tmp=max(tmp,dp[i1][j1-1][i2-1][j2]);
tmp=max(tmp,dp[i1][j1-1][i2][j2-1]);
if(i1==i2&&j1==j2)
dp[i1][j1][i2][j2]=tmp+a[i1][j1];
else
dp[i1][j1][i2][j2]=tmp+a[i1][j1]+a[i2][j2];
}
}
printf("%d\n",dp[n][n][n][n]);
}
}
降维:
f[k][i][j] = max { f[k-1][i][j], f[k-1][i-1][j-1], f[k-1][i-1][j],f[k-1][I][j-1] } + (i==j ? a[k-i][i] : a[k-i+1][i]+a[k-j+1][j])
f[k][i][j]表示走了k步,第一条路向右走i步,第二条路向右走j步。
每条路的每个位置都可以从它的上方或左方得到,所以max{}里会有四个状态。还有
如果两条路走到了同一位置,那么该位置的数只加一次.