dp优化--斜率
2012-08-25 21:33
316 查看
给出学习的连接:
http://www.notonlysuccess.com/index.php/dp_optimize/
hdu 2993:
// poi可以不存
// 注意两种删点,最优值(左边),凹形函数(右边)
hdu4258:(http://serjudging.vanb.org/?p=359)
最原始的dp方程:dp[i]=min{dp[j-1]+(x[i]-x[j])^2+c} , dp[i]是i的最优值,j<=i,显然是n^2的,需要优化....
优化:假设k<j<i, 对于i来说,如果j点决策比k点好,即根据上面的方程j点算出来<k点,如下...
dp[j-1]+(x[i]-x[j])^2+c < dp[k-1]+(x[i]-x[k])^2+c...展开,化简...
dp[j-1]+x[j]^2-2*x[i]*x[j]<dp[k-1]+x[k]^2-2*x[i]*x[k]...移项...
dp[j-1]+x[j]^2-(dp[k-1]+x[k]^2)<x[i]*(2*x[j]-2*x[k])....这里将dp[j-1]+x[j]^2视为Y[j],2*x[j]视为X[j]...得到
Y[j]-Y[k]<x[i]*(X[j]-X[k])...因为X[j]-X[k]>0...可以除过去...得到...注意x和X是不同的....
(Y[j]-Y[k])/(X[j]-X[k])<x[i]....视左边的为g[j, k]...注意要保证j,k顺序,保证X[j]-X[k]>0
接下来, 关键的来了:如今从左到右,还是设k<j<i,若是g[i,j]<g[j,k],那么j点便永远不成能成为最优解,可以直接将它踢出我们的最优解集。为什么呢?
我们假设g[i,j]<x[i],那么就是说i点要比j点优,打消j点。
若是g[i,j]>=x[i],那么j点此时是比i点要更优,然则同时g[j,k]>g[i,j]>x[i]。这申明还有k点会比j点更优,同样打消j点。
打消多余的点,这便是一种优化!
于是对于这题我们对于斜率优化做法可以总结如下:
1,用一个单调队列来保护解集。
2,假设队列中从头到尾已经有元素a b c。那么当d要入队的时辰,我们保护队列的上凸性质,即若是g[d,c]<g[c,b],那么就将c点删除。直到找到g[d,x]>=g[x,y]为止,并将d点参加在该地位中。
3,求解时,从队头开端,若是已有元素a b c,当i点请求解时,若是g[b,a]<x[i],那么申明b点比a点更优,a点可以打消,于是a出队。最后dp[i]的决策就是最左边的那个点。
http://www.notonlysuccess.com/index.php/dp_optimize/
hdu 2993:
#include "cstdio" #include "iostream" #include "algorithm" using namespace std; typedef pair<int, int> point; typedef __int64 ll; const int N = 111111; point poi ; int sum ; ll cross(point a, point b, point c){ ll x0 = b.first - a.first, y0 = b.second - a.second, x1 = c.first - a.first, y1 = c.second - a.second; return x0*y1 - x1*y0; } int bsearch(int l, int r, point p){ while(l<r){ int mid = (l+r)>>1; if(cross(poi[mid], poi[mid+1], p) < 0) { r = mid; } else { l = mid+1; } } return l; } int GetInt(){ char ch=getchar(); while(ch<'0'||ch>'9')ch=getchar(); int num=0; while(ch>='0'&&ch<='9'){ num=num*10+ch-'0'; ch=getchar(); } return num; } int main() { int n, k, i, j, l, r; double ans, tmp; point curp, newp; while(~scanf("%d%d", &n, &k)) { sum[0] = 0; for(i = 1; i <= n; ++i){ sum[i] = GetInt(); sum[i] += sum[i-1]; } ans = 0; l = 1; r = 0; for(i = k; i <= n; ++i){ newp.first = i-k; newp.second = sum[i-k]; curp.first = i; curp.second = sum[i]; while(r>l && cross(poi[r-1], poi[r], newp)<0) { --r; } poi[++r] = newp; for(j = l; j < r && cross(poi[j], poi[j+1], curp) >= 0; ++j) ; l = j; // n // l = bsearch(l, r, curp); // n // l = bsearch(1, r, curp); // nlg(n) tmp = (double)(poi[l].second-sum[i])/(poi[l].first - i); if(tmp>ans) { ans = tmp; } } printf("%.2lf\n", ans); } return 0; }
// poi可以不存
// 注意两种删点,最优值(左边),凹形函数(右边)
hdu4258:(http://serjudging.vanb.org/?p=359)
最原始的dp方程:dp[i]=min{dp[j-1]+(x[i]-x[j])^2+c} , dp[i]是i的最优值,j<=i,显然是n^2的,需要优化....
优化:假设k<j<i, 对于i来说,如果j点决策比k点好,即根据上面的方程j点算出来<k点,如下...
dp[j-1]+(x[i]-x[j])^2+c < dp[k-1]+(x[i]-x[k])^2+c...展开,化简...
dp[j-1]+x[j]^2-2*x[i]*x[j]<dp[k-1]+x[k]^2-2*x[i]*x[k]...移项...
dp[j-1]+x[j]^2-(dp[k-1]+x[k]^2)<x[i]*(2*x[j]-2*x[k])....这里将dp[j-1]+x[j]^2视为Y[j],2*x[j]视为X[j]...得到
Y[j]-Y[k]<x[i]*(X[j]-X[k])...因为X[j]-X[k]>0...可以除过去...得到...注意x和X是不同的....
(Y[j]-Y[k])/(X[j]-X[k])<x[i]....视左边的为g[j, k]...注意要保证j,k顺序,保证X[j]-X[k]>0
接下来, 关键的来了:如今从左到右,还是设k<j<i,若是g[i,j]<g[j,k],那么j点便永远不成能成为最优解,可以直接将它踢出我们的最优解集。为什么呢?
我们假设g[i,j]<x[i],那么就是说i点要比j点优,打消j点。
若是g[i,j]>=x[i],那么j点此时是比i点要更优,然则同时g[j,k]>g[i,j]>x[i]。这申明还有k点会比j点更优,同样打消j点。
打消多余的点,这便是一种优化!
于是对于这题我们对于斜率优化做法可以总结如下:
1,用一个单调队列来保护解集。
2,假设队列中从头到尾已经有元素a b c。那么当d要入队的时辰,我们保护队列的上凸性质,即若是g[d,c]<g[c,b],那么就将c点删除。直到找到g[d,x]>=g[x,y]为止,并将d点参加在该地位中。
3,求解时,从队头开端,若是已有元素a b c,当i点请求解时,若是g[b,a]<x[i],那么申明b点比a点更优,a点可以打消,于是a出队。最后dp[i]的决策就是最左边的那个点。
#include "cstdio" #include "iostream" using namespace std; typedef __int64 ll; typedef pair<ll, ll> pp; const int N = 1111111; ll po , qu , dp ; ll gg(int i, int j){ ll yi = dp[i-1] + po[i]*po[i], yj = dp[j-1] + po[j]*po[j], xi = 2*po[i], xj=2*po[j]; return (yi-yj)/(xi-xj); } ll check(pp p1, pp p2){ return (p1.second*p2.first-p2.second*p1.first); } ll calc(int i, int j, int k){ return (dp[j-1]+(po[i]-po[j])*(po[i]-po[j]))-(dp[k-1]+(po[i]-po[k])*(po[i]-po[k])); } ll GetLL(){ char ch=getchar(); while(ch<'0'||ch>'9') ch=getchar(); ll num=0; while(ch>='0'&&ch<='9'){ num=num*10+ch-'0'; ch=getchar(); } return num; } int main(){ int i, n, c, l, r; // freopen("covered.in", "r", stdin); while(scanf("%d%d", &n, &c) && n+c) { for(i=1; i<=n; ++i) { po[i] = GetLL(); // 外挂 // scanf("%I64d", &po[i]); } l=0; r=-1; for(i=1; i<=n; ++i) { dp[i]=0; while(l<r && gg(i, qu[r])<gg(qu[r], qu[r-1])) { --r; } qu[++r]=i; while(l<r && calc(i, qu[l+1], qu[l])<0) { ++l; } dp[i] = dp[qu[l]-1]+(po[i]-po[qu[l]])*(po[i]-po[qu[l]]) + c; // printf("%d %d %I64d\n", i, qu[l], dp[i]); } printf("%I64d\n", dp ); } return 0; }
相关文章推荐
- POJ 3709 K-Anonymous Sequence (斜率优化DP)
- HDU 3507 Print Article(斜率DP优化)
- HDU 3045 DP斜率优化 解题报告
- hdu 4258(斜率优化DP)
- hdu3507 斜率优化dp
- 【HDU3507】【斜率优化DP】Print Article题解
- hdu 2829 Lawrence 斜率优化dp
- BZOJ3156: 防御准备 【斜率优化dp】
- 斜率优化第一题! HDU3507 | 单调队列优化DP
- 【斜率优化dp】poj 1260 Pearls
- [apio2010]特别行动队(斜率优化的dp)
- HDU3507(dp + 斜率优化dp)
- HNOI 2008 玩具装箱Toy 斜率优化DP
- bzoj 3156: 防御准备【斜率优化dp】
- hdu3507Print Article(斜率优化dp)
- bzoj 1492: [NOI2007]货币兑换Cash【贪心+斜率优化dp+cdq】
- BZOJ2726:任务安排(DP+斜率优化+二分)
- BZOJ 1096 [ZJOI2007]仓库建设 斜率优化dp
- DP斜率优化总结
- 【BZOJ3675】【APIO2014】序列分割 [斜率优化DP]