牧场物语(难题)

小茗同学正在玩牧场物语。该游戏的地图可看成一个边长为n的正方形。
小茗同学突然心血来潮要去砍树,然而,斧头在小茗的右下方。
小茗是个讲究效率的人,所以他会以最短路程走到右下角,然后再返回到左上角。并且在路上都会捡到/踩到一些物品,比如说花朵,钱和大便等。
物品只能被取最多一次。位于某个格子时,如果格子上还有物品,就一定要取走。起点和终点上也可能有物品。
每种物品我们将为其定义一个价值,当然往返之后我们取得的物品的价值和越大越好。但是小茗同学正在认真地玩游戏,请你计算出最大的价值和。
题解:(这个题我不会做,只能看题解写在博客里经常看看,慢慢理解)
这个题有点像两个人一起吃金币,怎么走吃到的金币最多。来回看成两个人一起出发到达终点,设定dp[i][j][k][l]表示第一个人走到了(i,j)第二个人走到(k,l)的最优方案,那么其每个人都有两种走法.时间复杂度和空间复杂度都不允许,所以要去简化。我们要dp的就是位置,又已知每次行走都是最短路,那么我们不妨设定dp[i][j][k]表示第一个人走到第i行,第二个人走到第j行,一共两个人一起走了k步的方案。我们可以通过k和i,j之间的关系计算出两个人现在的位置,同理,对四种走法dp一下转移即可。
代码如下:
#include<stdio.h>
#include<string.h>
#include
#define ll long long
using namespace std;
ll v[110][110];
ll f[210][110][110];
int main()
{
int t,n,m,c;
int i,j,k;
while(scanf("%d",&n)!=EOF)
{
c=n+n-1;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
scanf("%I64d",&v[i][j]);
memset(f,-0x3f3f3f3f,sizeof(f));
f[1][1][1]=v[1][1];
for(k=2;k<=c;k++)
{
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(i!=j)
f[k][i][j]=max(max(f[k-1][i-1][j],f[k-1][i][j-1]),max(f[k-1][i][j],f[k-1][i-1][j-1]))+v[i][k-i+1]+v[j][k-j+1];
else
f[k][i][j]=max(max(f[k-1][i-1][j],f[k-1][i][j-1]),max(f[k-1][i][j],f[k-1][i-1][j-1]))+v[i][k-i+1];
}
printf("%I64d\n",f[c][n][n]);
}
return 0;
}
运用滚动数组优化的的代码:
#include<stdio.h>
#include<string.h>
#include
#define ll long long
using namespace std;
ll v[110][110];
ll f[5][110][110];
int main()
{
int t,n,m,c;
int i,j,k;
while(scanf("%d",&n)!=EOF)
{
c=n+n-1;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
scanf("%I64d",&v[i][j]);
memset(f,-0x3f3f3f3f,sizeof(f));
f[0][1][1]=v[1][1];
int kk=0;
for(k=2;k<=c;k++)
{
kk=kk^1;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(i!=j)
f[kk][i][j]=max(max(f[kk1][i-1][j],f[kk1][i][j-1]),max(f[kk1][i][j],f[kk1][i-1][j-1]))+v[i][k-i+1]+v[j][k-j+1];
else
f[kk][i][j]=max(max(f[kk1][i-1][j],f[kk1][i][j-1]),max(f[kk1][i][j],f[kk1][i-1][j-1]))+v[i][k-i+1];
}
printf("%I64d\n",f[kk][n][n]);
}
return 0;
}

发布了23 篇原创文章 · 获赞 0 · 访问量 329

猜你喜欢

转载自blog.csdn.net/qq_45762392/article/details/105254946
今日推荐