uestc599最小花费【单调队列优化dp】

来源:互联网 发布:lol挂机软件2017 编辑:程序博客网 时间:2024/06/09 18:27

单调队列优化dp

单调队列是一种严格单调的队列,可以单调递增,也可以单调递减。队首位置保存的是最优解,第二个位置保存的是次优解,ect。。。
单调队列可以有两个操作:
1、插入一个新的元素,该元素从队尾开始向队首进行搜索,找到合适的位置插入之,如果该位置原本有元素,则替换它。
2、在过程中从队首删除不符合当前要求的元素。
单调队列实现起来可简单,可复杂。简单的一个数组,一个head,一个tail指针就搞定。复杂的用双向链表实现。
用处:
1、保存最优解,次优解,ect。
2、利用单调队列对dp方程进行优化,可将O(n)复杂度降至O(1)。也就是说,将原本会超时的N维dp降优化至N-1维,以求通过。这也是我想记录的重点
是不是任何DP都可以利用单调队列进行优化呢?答案是否定的。
记住!只有形如 dp[i]=max/min (f[k]) + g[i]  (k<i && g[i]是与k无关的变量)才能用到单调队列进行优化。
优化的对象就是f[k]。
以上内容转载自:点击打开链接

UESTC599 最小花费

最少花费

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

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

Input

第一行一个整数TT(T150T≤150),表示数据组数。

每组第一行有33个整数NN(1N10001≤N≤1000), KK(0K10000≤K≤1000), AA(0A10000≤A≤1000)。

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

Output

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

Sample input and output

Sample InputSample Output
21 1 113 1 101 2 3
02

Source

UESTC Training for Dynamic Programming

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#include<cmath>#include<queue>#include<list>#include<vector>#define inf 0x3f3f3f3f using namespace std;const int maxn = 1010;int a,n,dl,q[maxn];long long  f[maxn][maxn],h[maxn];// dp[i][j]=min(dp[i-1][k]+A*(j-k)+X);// dp[i][j]=min(dp[i-1][k]+A*j-A*k+x);// F[i-1][k]=dp[i-1][k]-A*k;// g[i-1][k]=A*j+X;//用单调队列优化k int main(){int t;scanf("%d", &t);while (t--){scanf("%d%d%d", &n,&dl,&a);for (int i=1;i<=n;++i){scanf("%d",&h[i]);}memset(f,0x3f,sizeof(f));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);}}long long ans=inf;for (int i=0;i<=1000;++i)ans=min(ans,f[n][i]);printf("%lld\n",ans);}return 0;}



0 0