noip2000 方格取数(多重DP)

题目链接: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{}里会有四个状态。还有
如果两条路走到了同一位置,那么该位置的数只加一次.



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值