【牛客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;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值