标签:
题目大意:
一个N个点的序列,要将他们全部覆盖,求总最少费用;费用计算: c+(x-y)2
分析:
我们假设k<j<i。如果在j的时候决策要比在k的时候决策好,那么也是就是dp[j]+M+(sum[i]-sum[j])^2<dp[k]+M+(sum[i]-sum[k])^2。(因为是最小花费嘛,所以优就是小于)
两边移项一下,得到:(dp[j]+num[j]^2-(dp[k]+num[k]^2))/(2*(num[j]-num[k]))<sum[i]。我们把dp[j]-num[j]^2看做是yj,把2*num[j]看成是xj。
那么不就是yj-yk/xj-xk<sum[i]么? 左边是不是斜率的表示?
那么yj-yk/xj-xk<sum[i]说明了什么呢? 我们前面是不是假设j的决策比k的决策要好才得到这个表示的? 如果是的话,那么就说明g[j,k]=yj-jk/xj-xk<sum[i]代表这j的决策比k的决策要更优。
关键的来了:现在从左到右,还是设k<j<i,如果g[i,j]<g[j,k],那么j点便永远不可能成为最优解,可以直接将它踢出我们的最优解集。为什么呢?
我们假设g[i,j]<sum[i],那么就是说i点要比j点优,排除j点。
如果g[i,j]>=sum[i],那么j点此时是比i点要更优,但是同时g[j,k]>g[i,j]>sum[i]。这说明还有k点会比j点更优,同样排除j点。
排除多余的点,这便是一种优化!
接下来看看如何找最优解。
设k<j<i。
由于我们排除了g[i,j]<g[j,k]的情况,所以整个有效点集呈现一种上凸性质,即k j的斜率要大于j i的斜率。
这样,从左到右,斜率之间就是单调递减的了。当我们的最优解取得在j点的时候,那么k点不可能再取得比j点更优的解了,于是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]<sum[i],那么说明b点比a点更优,a点可以排除,于是a出队。最后dp[i]=getDp(q[head])。
原文链接 http://www.cnblogs.com/ka200812/archive/2012/08/03/2621345.html
对于这道题: f[i] = min(f[j] + (a[i]-a[j+1]) ^ 2+c) (N^2)
公式变形+数形结合:f[i] = min{f[j] + a[j+1]^2 - 2*a[i]*a[j+1] + a[i]^2 +C}
令x = a[j+1],y = f[j] + a[j+1]^2;
f[i] = y - 2*a[i]*x + a[i]^2 + C;
1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 #include<iostream> 5 #include<algorithm> 6 #include<queue> 7 #define maxn 1000005 8 using namespace std; 9 typedef long long LL; 10 LL n,a[maxn]; 11 LL dp[maxn]; 12 int que[maxn]; 13 double judge_k(int x,int y) 14 { 15 return (double)(dp[x]+a[x+1]*a[x+1]-(dp[y]+a[y+1]*a[y+1]))/((double)(2.0*(a[x+1]-a[y+1]))); 16 } 17 int main() 18 { 19 int c; 20 while(scanf("%I64d %d",&n,&c)!=EOF) 21 { 22 if(n==0&&c==0) 23 break; 24 for(int i=1;i<=n;i++) 25 scanf("%I64d",&a[i]); 26 dp[0]=0;dp[1]=c; 27 que[0]=0; 28 que[1]=1; 29 int l=0,r=1; 30 for(int i=2;i<=n;i++) 31 { 32 while(l<r&&judge_k(que[l],que[l+1])<=a[i]) l++; 33 dp[i]=dp[que[l]]+c+(a[i]-a[que[l]+1])*(a[i]-a[que[l]+1]); 34 while(l<r&&judge_k(que[r],i)<=judge_k(que[r],que[r-1])) r--; 35 que[++r]=i; 36 } 37 printf("%I64d\n",dp[n]); 38 } 39 return 0; 40 }
标签:
原文地址:http://www.cnblogs.com/tsw123/p/4412195.html