UESTC - 594 我要长高(DP+滚动数组优化+单调队列优化)
2018-01-07 21:37
288 查看
韩父有NN个儿子,分别是韩一,韩二…韩NN。由于韩家演技功底深厚,加上他们间的密切配合,演出获得了巨大成功,票房甚至高达20002000万。舟子是名很有威望的公知,可是他表面上两袖清风实则内心阴暗,看到韩家红红火火,嫉妒心遂起,便发微薄调侃韩二们站成一列时身高参差不齐。由于舟子的影响力,随口一句便会造成韩家的巨大损失,具体亏损是这样计算的,韩一,韩二…韩NN站成一排,损失即为C×C×(韩ii与韩i+1i+1的高度差(1≤i<N1≤i<N))之和,搞不好连女儿都赔了.韩父苦苦思索,决定给韩子们内增高(注意韩子们变矮是不科学的只能增高或什么也不做),增高11cm是很容易的,可是增高1010cm花费就很大了,对任意韩ii,增高HHcm的花费是H2H2.请你帮助韩父让韩家损失最小。
题意很清楚,但是一上来做的话很容易没有思路,但是如果知道这是一道dp题之后就好入手了很多。很显然的,我们从韩1到韩n计算,韩i子的情况一定与韩i-1子的状况有关,递归关系很明显,这里用dp【i】【j】表示韩i子的身高为j时的结果,可以写出dp公式:dp[i][j]=Min(dp[i][j], (dp[i-1][k]+Abs(j-k)*C+(h[i]-j)*(h[i]-j))); 这里dp【i-1】【k】表示韩i-1子身高为k时的结果(已知),h【i】存的是韩i的身高。看一下这个式子里的未知量:i、j、k,需要三重循环O(n*100*100),超时。但是我还是把它写了下来,因为单论这一部分的dp而言就够一个题了,再加上后面会提到的单调队列优化的话,我一上来实在是看不懂,跨度太大跳不过去,只能自己按部就班慢慢优化出来。另外,我觉得那个100可以稍微优化上一点点,也就是上下限换成h【】的最小最大值,说不定能过的,然而并没有。
对于找出来的dp公式先去掉Abs()分解开:
1、韩i比韩i-1高时(j>k) dp[i][j]=Min(dp[i][j], dp[i-1][k]-k*C+j*C+X);
2、韩i比韩i-1矮时(j<k) dp[i][j]=Min(dp[i][j], dp[i-1][k]+k*C-j*C+X); (X=(h[i]-j)*(h[i]-j))
然后就是滚动数组+单调队列优化dp了。先单独说下知识点的问题:滚动数组,并不算陌生,之前用过一两次,前天我再看LCS的时候也见到过滚动数组的使用;滚动数组并不算是一个知识点,而是一个工具,优化空间的工具。做dp的的话,方程难找是另一个层次的问题了,可在有了方程的情况下,数组开不出来实在是很难受的,这时候往往就要滚动数组了。这个题中n*100的数组是能开的,但是看的题解上直接就是最优方法,也就学了过来。单调队列优化dp,单调队列是专门练过的,比较熟悉,但是想到优化dp我是很懵逼的,做完了这题后也算是初步了解;就这个题而言,对于韩i子,我们需要的是(1...100)枚举韩i的身高j,然后里面套一层(1...100)枚举韩i-1的身高k并从中找出与j相配的最合适的k(也就是dp[i-1][k]±k*C最小值),而我们观察上面拆分了的两个式子,每一种都情况中的j,所要匹配的k实际上不是全部(1...100),而只是其中的一部分,而两者恰好可以用一个单调队列来维护,具体在代码中体现。两个,分别是二维数组和滚动数组(也是二维,不过只有2,相当于一维了pre[]+now[])两种方案。还有更加精简的,直接用一个最小值minn维护就可以了,不再写了,稍微改动即可。
超时代码如下:
AC代码如下:(二维数组+单调队列优化)
AC代码2(滚动数组+单调队列优化)
题意很清楚,但是一上来做的话很容易没有思路,但是如果知道这是一道dp题之后就好入手了很多。很显然的,我们从韩1到韩n计算,韩i子的情况一定与韩i-1子的状况有关,递归关系很明显,这里用dp【i】【j】表示韩i子的身高为j时的结果,可以写出dp公式:dp[i][j]=Min(dp[i][j], (dp[i-1][k]+Abs(j-k)*C+(h[i]-j)*(h[i]-j))); 这里dp【i-1】【k】表示韩i-1子身高为k时的结果(已知),h【i】存的是韩i的身高。看一下这个式子里的未知量:i、j、k,需要三重循环O(n*100*100),超时。但是我还是把它写了下来,因为单论这一部分的dp而言就够一个题了,再加上后面会提到的单调队列优化的话,我一上来实在是看不懂,跨度太大跳不过去,只能自己按部就班慢慢优化出来。另外,我觉得那个100可以稍微优化上一点点,也就是上下限换成h【】的最小最大值,说不定能过的,然而并没有。
对于找出来的dp公式先去掉Abs()分解开:
1、韩i比韩i-1高时(j>k) dp[i][j]=Min(dp[i][j], dp[i-1][k]-k*C+j*C+X);
2、韩i比韩i-1矮时(j<k) dp[i][j]=Min(dp[i][j], dp[i-1][k]+k*C-j*C+X); (X=(h[i]-j)*(h[i]-j))
然后就是滚动数组+单调队列优化dp了。先单独说下知识点的问题:滚动数组,并不算陌生,之前用过一两次,前天我再看LCS的时候也见到过滚动数组的使用;滚动数组并不算是一个知识点,而是一个工具,优化空间的工具。做dp的的话,方程难找是另一个层次的问题了,可在有了方程的情况下,数组开不出来实在是很难受的,这时候往往就要滚动数组了。这个题中n*100的数组是能开的,但是看的题解上直接就是最优方法,也就学了过来。单调队列优化dp,单调队列是专门练过的,比较熟悉,但是想到优化dp我是很懵逼的,做完了这题后也算是初步了解;就这个题而言,对于韩i子,我们需要的是(1...100)枚举韩i的身高j,然后里面套一层(1...100)枚举韩i-1的身高k并从中找出与j相配的最合适的k(也就是dp[i-1][k]±k*C最小值),而我们观察上面拆分了的两个式子,每一种都情况中的j,所要匹配的k实际上不是全部(1...100),而只是其中的一部分,而两者恰好可以用一个单调队列来维护,具体在代码中体现。两个,分别是二维数组和滚动数组(也是二维,不过只有2,相当于一维了pre[]+now[])两种方案。还有更加精简的,直接用一个最小值minn维护就可以了,不再写了,稍微改动即可。
超时代码如下:
#include<stdio.h> const int MAX=50010; const int INF=1e9; int N, C; int h[MAX]; int dp[MAX][110];//韩i身高为j时 int Abs(int x) { if(x>0) return x; return -x; } int Min(int x, int y) { if(x>y) return y; return x; } int main() { while(scanf("%d%d", &N, &C)) { int left=1e9, right=0; for(int i=1; i<=N; i++) { scanf("%d", &h[i]); if(left>h[i]) left=h[i]; if(right<h[i]) right=h[i]; } for(int i=0; i<=N; i++)//初始化为极大值 { for(int j=0; j<=100; j++) { dp[i][j]=INF; } } for(int i=left; i<=right; i++)//初始化dp[0][] dp[0][i]=0; for(int i=1; i<=N; i++)//韩i { for(int j=h[i]; j<=right; j++)//韩i的身高 { for(int k=h[i-1]; k<=right; k++)//韩i-1的身高 { dp[i][j]=Min(dp[i][j], (dp[i-1][k]+Abs(j-k)*C+(h[i]-j)*(h[i]-j))); //动规 公式 } } } int ans=dp [right]; for(int i=left; i<=right; i++) { if(ans>dp [i]) ans=dp [i]; } printf("%d\n", ans); } return 0; }
AC代码如下:(二维数组+单调队列优化)
#include<cstdio> using namespace std; const int MAX=50010; const int INF=1e9; int N, C; int dp[MAX][110];//韩i身高为j时 int q[MAX]; int Min(int x, int y) { if(x<y) return x; return y; } int main() { while(~scanf("%d%d", &N, &C) && (N+C)) { int head=0, tail=0; int x; scanf("%d", &x); for(int i=0; i<=100; i++)//对韩1 初始化 { if(i<x) dp[1][i]=INF; else dp[1][i]=(i-x)*(i-x); } for(int i=2; i<=N; i++)//韩2——》韩n { scanf("%d", &x); head=tail=0; for(int j=0; j<=100; j++)//韩i比韩i-1高时 { int temp=dp[i-1][j]-j*C;//韩i-1的半个状态 while(head<tail && temp<q[tail-1]) tail--; q[tail++]=temp; if(j>=x)//求韩i身高为j时 dp[i][j]=q[head]+j*C+(x-j)*(x-j); else dp[i][j]=INF; } head=tail=0; for(int j=100; j>=0; j--)//韩i比韩i-1矮时 { int temp=dp[i-1][j]+j*C; while(head<tail && temp<q[tail-1]) tail--; q[tail++]=temp; if(j>=x)//求韩身高为j时 dp[i][j]=Min(dp[i][j], q[head]-j*C+(x-j)*(x-j)); else dp[i][j]=INF; } } int ans=INF; for(int i=0; i<=100; i++) { ans=Min(ans, dp [i]); } printf("%d\n", ans); } return 0; }
AC代码2(滚动数组+单调队列优化)
#include<cstdio> using namespace std; const int MAX=50010; const int INF=1e9; int N, C; int dp[2][110];//韩i身高为j时 int q[MAX]; int Min(int x, int y) { if(x<y) return x; return y; } int main() { while(~scanf("%d%d", &N, &C) && (N+C)) { int head=0, tail=0; int x; scanf("%d", &x); int now=1; for(int i=0; i<=100; i++)//对韩1 初始化 { if(i<x) dp[now][i]=INF; else dp[now][i]=(i-x)*(i-x); } for(int i=2; i<=N; i++)//韩2——》韩n { scanf("%d", &x); head=tail=0; now=now^1;//now=now%2; now=1-now; 均可 for(int j=0; j<=100; j++)//韩i比韩i-1高时 { int temp=dp[now^1][j]-j*C;//韩i-1的半个状态 while(head<tail && temp<q[tail-1]) tail--; q[tail++]=temp; if(j>=x)//求韩i身高为j时 dp[now][j]=q[head]+j*C+(x-j)*(x-j); else dp[now][j]=INF; } head=tail=0; for(int j=100; j>=0; j--)//韩i比韩i-1矮时 { int temp=dp[now^1][j]+j*C; while(head<tail && temp<q[tail-1]) tail--; q[tail++]=temp; if(j>=x)//求韩身高为j时 dp[now][j]=Min(dp[now][j], q[head]-j*C+(x-j)*(x-j)); else dp[now][j]=INF; } } int ans=INF; for(int i=0; i<=100; i++) { ans=Min(ans, dp[now][i]); } printf("%d\n", ans); } return 0; }
相关文章推荐
- 【单调队列优化dp】uestc 594 我要长高
- UESTC 594 我要长高 (单调队列优化DP)
- UESTC - 594 我要长高 单调队列优化DP
- UESTC 594 我要长高 单调队列优化DP
- UESTC-594 我要长高(动态规划+单调队列优化)
- NKOJ 4244 (HAOI 2008) 木棍分割 (二分答案+DP+单调队列+前缀和优化+滚动数组)
- uestc 594 我要长高 单调队列优化
- Codeforces 373E Watching Fireworks is Fun【思维+单调队列优化Dp+滚动数组】
- HAOI2008 木棍分割 二分答案 前缀和优化 单调队列 滚动数组
- CDOJ 我要长高 (单调队列优化DP)
- UESTC 880 生日礼物 --单调队列优化DP
- bzoj1499(这道题改天重做,dp+单调队列优化)
- hdu3401trade【单调队列优化dp】
- bzoj1233 [Usaco2009Open]干草堆tower(单调队列优化DP)
- POJ2373...单调队列优化DP...
- hdu 2191 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活 单调队列优化dp
- Hdu 3401 题解 单调队列优化DP
- 【bzoj3831】[Poi2014]Little Bird 单调队列优化dp
- hdu3401 Trade 单调队列优化dp
- 【例题】【单调队列优化DP】NKOJ2151 烽火传递