计蒜客-面码的游戏(dp)

题目网址https://nanti.jisuanke.com/t/28475

一开始把题目看错了,写了个简单dp,后来才发现

题意是:从n行任意位置走,向上向左走,然后走到(1,1),再从(1,1)位置向下向右走到m列,一个格子第一次走获得a【i】【j】的值,第二次走获得b【i】【j】的值;

队友和hls在网络流了半天,感觉有戏,但是后来发现我把m列读成了n行,(差点被打),然后继续流,

我一直在想dp,我思维受限,把两次走法分开,按照正常思维推,但是这样状态很难转移。后来看了题解才了然。

思路: 将第一次和第二次的路线合在一个数组里面,再通过步数来降维

   dp【i】【j】【k】 表示从(1,1)走了i步,第一次走到j行时,并且第二次走到k行时,当前获得的最大值。

其实两次走,我们都可以看成是从(1,1)出发向下或者向右出发,到达n行,m列结束,如果从(1,1)走了i步,当前在j行,那么我们可以推断出,当前位置为( j , i - j +1),同样可以推断第二次位置在(k,i - k + 1),这样可以退出转移方程为

 dp【i】【j】【k】 = dp【i】【j+x】【k+y】 + a[j][i - j +1 ]+ ( j==k? b[j][i - j +1 ]:a[k][i-k+1]) 

这个x和y表示,ijk可以由i-1四种方式转移而来,即第一次的向下或者向右,与第二次的向下或者向右。

还有一个需要注意的问题是,最后更新答案的时候,我之前一直不明白为何标程给的是当 i = n+m-1 时更新答案,但是跟hls交流我就明白了,因为在数组a,b超出n,m的部分的值为0,所以一直走也是可以的

那为什么不能是 i==n并且 i-k-1==m时更新呢?我们需要注意,dp保存的第一次和第二次的i是一样的,所以会出现一种情况,就是比如我们当前走了i1步到m列已经是最优解了,但是i1步的n行还不是最优解,这样我们如果让i1增加的话,可以让 k不变,一直往右走加0,这样n行还可以继续走,这样就可以让第二次伪停止,来取得最优解。

这样看来我们需要把原来条件改成 i>=n并且 i-k-1>=m  或者干脆 i ==n+m-1  就可以了

代码如下

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL INF=161168601842738790ll;
int n,m;
LL f[130][130][130];
LL a[130][130],b[130][130];
int main()
{
    scanf("%d%d",&n,&m);
    memset(f,0,sizeof f);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            scanf("%lld",&a[i][j]);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            scanf("%lld",&b[i][j]);
    for(int i=0;i<=125;i++)
        for(int j=0;j<=125;j++)
            for(int k=0;k<=125;k++)
                f[i][j][k]=-INF;
    f[1][1][1]=a[1][1]+b[1][1];
    int t1,t2;
    LL ans=-INF;        
    for(int i=2;i<n+m;i++)
        for(int j=1;j<=i;j++)
            for(int k=1;k<=i;k++)
            {
                t1=i+1-j;
                t2=i+1-k;
                f[i][j][k]=max(f[i][j][k],f[i-1][j-1][k-1]);
                f[i][j][k]=max(f[i][j][k],f[i-1][j][k-1]);
                f[i][j][k]=max(f[i][j][k],f[i-1][j-1][k]);
                f[i][j][k]=max(f[i][j][k],f[i-1][j][k]);
                if(j==k)
                    f[i][j][k]+=a[j][t1]+b[j][t1];
                else
                    f[i][j][k]+=a[j][t1]+a[k][t2];
                if (i == n + m - 1){
                    ans = max(ans, f[i][j][k]);
                }
            }
    cout<<ans<<endl;
    return 0;
}       

猜你喜欢

转载自blog.csdn.net/sinat_36215255/article/details/81143004