本文主要是介绍【牛客oj】跳跳跳(区间dp),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
链接:登录—专业IT笔试面试备考平台_牛客网
来源:牛客网
题目描述
dd在玩跳格子游戏,具体游戏规则如下,
n个格子呈环形分布,顺时针方向分别标号为1∼n,其中1和n相邻,每个格子上都有一个正整数a[i],玩家可以选择一个点作为起点开始跳n下,第i次跳跃,玩家只可以选择当前位置左边或右边最近且尚未被跳跃过的位置进行一次跳跃,并获得i×a[p]的得分,其中ppp为第 i次跳跃的位置。
dd很鸡贼,想赢又不想动脑子,她希望你能给她规划路线以确保她的胜利
输入描述:
第一行一个数n(1≤n≤2000) 接下来一行n个数,表示a[i](1≤a[i]≤2000)
输出描述:
一个数,表示dd可能获得的最高分
示例1
输入
3 1 1 1
输出
6
说明
可能方案 1->2->3 1->3->2 2->1->3 2->3->1 3->1->2 3->2->1 (以上数字表示格子标号)
答案均为 1*1+2*1+3*1=6
最优方案不唯一,最优答案唯一
示例2
输入
3 1 2 3
输出
14
说明
方案:1->2->3(数字对应格子标号)
答案:1*1+2*2+3*3=14
最优方案唯一
解题思路:
一道区间dp的题目+利用开二倍数组处理环的问题
先说一下用二倍数组处理环的问题,这是最常用的方式处理环了
a[i+n]=a[i]
(ps没有平板这图画的也太丑了,应该凑合能看懂)这n+1的位置其实就相当于2的位置,这样开到2n可以保证从1~n遍历都能是个闭合的环(说的不太清楚)
再说区间dp部分,dp[i][j]表示当前走完的点中i为左端点,j为右端点时获得的最高分,确定了i,j之后,可以确定当前走完了j-i+1步,并且当前停留在i或者j这个位置,因为每次可以向左或者向右走,当前的状态是由len-1也就是j-i这么大小的区间向左或者向右扩充一个位置得到的,那么可以得到递推方程
dp[i][j]=max(dp[i+1][j]+a[i]*(j-i+1),dp[i][j-1]+a[j]*(j-i+1))
需要注意我们在枚举时数据的范围,详细看代码,剩下就没啥问题了
下面附上ac代码
#include <bits/stdc++.h>
using namespace std;
int n,a[4005],dp[4005][4005];
int main()
{while(scanf("%d",&n)!=EOF){for(int i=1;i<=n;i++) //开二倍数组处理环{scanf("%d",&a[i]);a[i+n]=a[i];}for(int len=1;len<=n;len++) //枚举区间长度{for(int i=1;i<=2*n-len+1;i++) //枚举区间起点{int j=i+len-1;dp[i][j]=max(dp[i+1][j]+a[i]*(j-i+1),dp[i][j-1]+a[j]*(j-i+1)); //状态转移}}int ans=0;for(int i=1;i<=n;i++) //寻找答案最大值{ans=max(ans,dp[i][i+n-1]);}printf("%d\n",ans);}//system("pause");return 0;
}
这篇关于【牛客oj】跳跳跳(区间dp)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!