noip2000 方格取数(多重DP)

来源:互联网 发布:整合网络推广方案ppt 编辑:程序博客网 时间:2024/05/21 09:10

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



原创粉丝点击