HDU3045 Picnic Cows (斜率DP优化)(数形结合)
2017-11-11 09:31
309 查看
转自PomeCat:
“DP的斜率优化——对不必要的状态量进行抛弃,对不优的状态量进行搁置,使得在常数时间内找到最优解成为可能。斜率优化依靠的是数形结合的思想,通过将每个阶段和状态的答案反映在坐标系上寻找解答的单调性,来在一个单调的答案(下标)队列中O(1)得到最优解。”
https://wenku.baidu.com/view/b97cd22d0066f5335a8121a3.html“一些试题中繁杂的代数关系身后往往隐藏着丰富的几何背景,而借助背景图形的性质,可以使那些原本复杂的数量关系和抽象的概念,显得直观,从而找到设计算法的捷径。”—— 周源《浅谈数形结合思想在信息学竞赛中的应用》
斜率优化的核心即为数形结合,具体来说,就是以DP方程为基础,通过变形来使得原方程形如一个函数解析式,再通过建立坐标系的方式,将每一个DP方程代表的状态表示在坐标系中,在确定“斜率”单调性的前提下,进行形如单调队列操作的舍解和维护操作。
一个算法总是用于解决实际问题的,所以结合例题来说是最好的:
Picnic Cows(HDU3045)
题目大意:给出一个有N (1<= N <=400000)个正数的序列,要求把序列分成若干组(可以打乱顺序),每组的元素个数不能小于T (1 < T <= N)。每一组的代价是每个元素与最小元素的差之和,总代价是每个组的代价之和,求总代价的最小值。
样例输入包含:
第一行 N
第二行 N个数,如题意
样例输出包含:
第一行 最小的总代价
分析:
首先,审题。可以打乱序列顺序,又知道代价为组内每个元素与最小值差之和,故想到贪心,先将序列排序(用STL sort)。
先从最简单的DP方程想起:
容易想到:
f[i] = min( f[j] + (a[j + 1 -> i] - Min k) ) (0 <= j < i)
– –> f[i] = min( f[j] + sum[i] - sum[j] - a[j + 1] * ( i - j ) )
Min k 代表序列 j + 1 -> i 内的最小值,排序后可以简化为a[j + 1]。提取相似项合并成前缀和sum。这个方程的思路就是枚举 j 不断地计算状态值更新答案。但是数据规模达到了 40000 ,这种以O(n ^ 2)为绝对上界方法明显行不通。所以接下来我们要引入“斜率”来优化。
首先要对方程进行变形:
f[i] = f[j] + sum[i] - sum[j] - a[j + 1] * ( i - j )
– –> f[i] = (f[j] - sum[j] + a[j + 1] * j) - i * a[j + 1] + sum[i]
(此步将只由i决定的量与只由j决定的量分开)
由于 sum[i] 在当前枚举到 i 的状态下是一个不变量,所以在分析时可以忽略(因为对决策优不优没有影响)(当然写的时候肯定不能忽略)
令 i = k
a[j + 1] = x
f[j] - sum[j] + a[j + 1] * j = y
f[i] = b
原方程变为
– –> b = y - k * x
移项
– –> y = k * x + b
是不是很眼熟? 没错,这就是直线的解析式。观察这个式子,我们可以发现,当我们吧许许多多的答案放在坐标系上构成点集,且枚举到 i 时,过每一个点的斜率是一样的!! 很抽象? 看图
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int maxn=800010; long long dp[maxn],q[maxn]; long long a[maxn],sum[maxn]; long long getdp(long long i,long long j) { return dp[j]+(sum[i]-sum[j])-a[j+1]*(i-j); } long long getdy(long long j,long long k)//得到 yj-yk k<j { return dp[j]-sum[j]+j*a[j+1]-(dp[k]-sum[k]+k*a[k+1]); } long long getdx(long long j,long long k)//得到 xj-xk k<j { return a[j+1]-a[k+1]; } int main() { long long i,j,n,k,head,tail,m; while(~scanf("%lld%lld",&n,&m)){ head=tail=0; sum[0]=q[0]=dp[0]=q[1]=0; for(i=1;i<=n;i++) scanf("%lld",&a[i]); sort(a+1,a+n+1); for(i=1;i<=n;i++) sum[i]=sum[i-1]+a[i]; for(i=1;i<=n;i++){ //删去队首斜率小于目前斜率的点 while(head<tail&&(getdy(q[head+1],q[head])<=i*getdx(q[head+1],q[head]))) head++; dp[i]=getdp(i,q[head]); j=i-m+1; if(j<m) continue; //接下来是对j而不是i进行处理 ,保证了间隔大于m-1的要求 while(head<tail&&(getdy(j,q[tail])*getdx(j,q[tail-1])<=getdy(j,q[tail-1])*getdx(j,q[tail]))) tail--; q[++tail]=j; } printf("%lld\n",dp ); } return 0; }
View Code
相关文章推荐
- hdu3045 Picnic Cows(斜率优化DP)
- 【HDU3045】【斜率优化DP】Picnic Cows题解
- 斜率优化DP 与数形结合思想
- hdu3045 Picnic Cows 斜率优化dp
- HDU3045——Picnic Cows(斜率优化DP)
- HDU 3045 DP 斜率优化 Picnic Cows
- HDU3045 Picnic Cows(斜率DP)
- HDU 3045 Picnic Cows (斜率优化DP)
- HDU 3045 Picnic Cows(斜率优化DP)
- HDU 3045 Picnic Cows(斜率优化DP)
- hdu 3045 Picnic Cows(斜率优化dp)
- UVA 1451 Average平均值 (数形结合,斜率优化)
- dp斜率优化 Hdu 3045(Picnic Cows)题解
- 斜率优化,数形结合(Average,uva 1451)
- HDU 3045 Picnic Cows【dp斜率优化】
- hdu 3045 Picnic Cows 斜率优化dp
- HDU-3045 Picnic Cows 斜率优化DP
- HDU 3045 Picnic Cows(斜率优化DP)
- hdu 3045 Picnic Cows 斜率优化 dp中有间隔限定
- hdu 3045 Picnic Cows(斜率优化DP)