UESTC_最少花费 2015 UESTC Training for Dynamic Programming<Problem D>

本文介绍了一道名为D-最少花费的算法题目,该题要求计算魔法师Bob跨越不同高度山脉所需的最小魔法值。文章详细阐述了使用动态规划与单调队列相结合的方法解决此问题的过程,并给出了完整的C++实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

D - 最少花费

Time Limit: 30000/10000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others)
Submit Status

Bob是一个魔法师。这天,他被N座山所阻挡,这些山排成一排,每座山有一个高度。Bob需要从左往右每次跳到相邻的一座山上,相邻的两座山的高度差不能超过K,当从高度差为D的一座山跳到另一座山时要花A×D的魔法值。Bob可以改变一座山的高度,但调整后的高度不能小于0或大于1000,改变S的高度需要花费S×S的魔法值。现在已知每座山的高度,求Bob跳完所有山后魔法值的最少花费。

Input

第一行一个整数T(T150),表示数据组数。

每组第一行有3个整数N(1N1000), K(0K1000), A(0A1000)。

接下来N个整数,按从左往右的顺序表示山的高度,山的高度在01000之间。

Output

对于每组数据,输出一个整数,表示最少花费。

Sample input and output

Sample InputSample Output
2
1 1 1
1
3 1 10
1 2 3
0
2

 

解题报告:

 我们令f( i , j ) 将第 i 座山高度改为 j 的最小花费.

  F( i , j ) = min ( f( i – 1 , k ) + abs ( j – k ) + (i – h[i]) ^ 2)

  不妨有 j > k

  F( i , j ) = min ( f( i – 1 , k ) – k ) + j + (i – h[i]) ^ 2

 即维护一个单调队列来更新 j > k的情况.

 J < k 的情况同理.

 

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
typedef long long ll;
using namespace std;
const int maxn = 1e3 + 50;
int a,n,dl,q[maxn];
ll  f[maxn][maxn],h[maxn];

int main(int argc,char *argv[])
{
  int Case;
  scanf("%d",&Case);
  while(Case--)
   {
         scanf("%d%d%d",&n,&dl,&a); //DL = deeplimit
         for(int i = 1 ; i <= n ; ++ i)
          scanf("%lld",&h[i]);
         for(int i = 1 ; i <= n ; ++ i)
          for(int j = 0 ; j <= 1000 ; ++ j)
           f[i][j] = 999999999999;
         for(int i = 0 ; i <= 1000 ; ++ i)
          f[1][i] = (i-h[1])*(i-h[1]);
         for(int i = 2 ; i <= n ; ++ i)
          {
                int front = 0 , rear = 0;
                for(int j = 0 ; j <= 1000 ; ++ j)
                 {
                       while(rear > front && f[i-1][q[rear-1]] - a*q[rear-1] >= f[i-1][j] - a*j)
                        rear--;
                       q[rear++] = j;
                       while(rear - front > 1 && j > q[front] + dl)
                        front++;
                       f[i][j] = min(f[i][j],(j-h[i])*(j-h[i])  +  f[i-1][q[front]] + (j - q[front]) * a);
           }
          front = rear = 0;
          for(int j = 1000 ; j >= 0 ; -- j)
           {
              while(rear > front && f[i-1][q[rear-1]] + q[rear-1]*a >= f[i-1][j] + j*a)
                  rear--;
                 q[rear++] = j;
                 while(rear - front > 1 && q[front] > j + dl)
                  front++;
                 f[i][j] = min(f[i][j],(j-h[i])*(j-h[i])  + f[i-1][q[front]] + (q[front] - j) * a );
           }
       }
      ll ans = 999999999999;
      for(int i = 0 ; i <= 1000 ; ++ i)
       ans = min(ans,f[n][i]);
      printf("%lld\n",ans);
   }
  return 0;
}

 

转载于:https://www.cnblogs.com/Xiper/p/4539614.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值