斜率优化DP

斜率优化DP 两步骤;

1.造出DP方程;

2.通过DP方程构造出一个斜率优化方程;

具体怎么构造呢?  如 两个点 a b;

构造出 DP(a)<DP(b)  然后通过这一式子,构造出一个下凸包(后面的边的斜率大于前面的边)

只有下凸包的点是可能作为状态转移方程的转移点,其他点都不可能。

然后,构造完后,  每一次更新的时候,就用head 和head+1两者进行比较,

如果DP(head+1)>DP(head)   那么将其出队 操作方法是 head++;

这里给出一道例题:

给出一个n个元素数组,将其分为几组,每一组算出其和的平方加上给定数m,将每一组的值求和然后输出,求最小值。

 1 #include<cstdio>
 2 #include<string.h>
 3 using namespace std;
 4 const int maxn=5e5+10;
 5 int sum[maxn];
 6 int f[maxn];
 7 int q[maxn];
 8 int xie(int x,int y)
 9 {   //虽说这里命名为斜率,但是得结合下面的区间合才能是斜率;
10     return f[y]-f[x]+sum[y]*sum[y]-sum[x]*sum[x];
11 }
12 int qu_num(int x,int y)
13 {   //区间合;
14     return sum[y]-sum[x];
15 }
16 void init()
17 {   //优化过的初始化;
18     memset(f,0,sizeof(f));
19     sum[0]=0;
20 }
21 int main()
22 {
23     int n,m,i;
24     while(scanf("%d%d",&n,&m)!=EOF){
25         init();
26         for(i=1;i<=n;i++){
27             int t;
28             scanf("%d",&t);
29             sum[i]=sum[i-1]+t;  //前缀和;
30         }
31         int head=0,tail=0;
32         for(i=1;i<=n;i++){
33             int k=sum[i]*2;   //这是斜率的一部分;
34             while(head<tail&&xie(q[head],q[head+1])<=k*qu_num(q[head],q[head+1]))
35                 head++; //假如head+1比head优,就将head出队,直到不优为止;
36                         //那为什么到不优的点之后,就可以停止了呢;
37                         //判断条件:sum[i]*2小于斜率;
38                         //因为这是一个凸包,斜率逐渐上升,既然head比head+1
39                         //不优的话,那么再后面的点所能计算出的斜率与该点比较
40                         //斜率会越来越大,而判断条件是:sum[i]*2小于斜率;
41                         //所以当前点肯定比后面的点更优,故可以在此停止搜索;
42                         //前提这是一个凸包;
43             f[i]=f[q[head]]+qu_num(q[head],i)*qu_num(q[head],i)+m;
44             while(head<tail){
45                 int a=xie(q[tail-1],q[tail])*qu_num(q[tail],i);
46                 int b=xie(q[tail],i)*qu_num(q[tail-1],q[tail]);
47                 if(a>=b) tail--;
48                 else break;
49                 //保证这是个向下凸包,为上面的搜索铺好前提;
50                 //这道题的第一个点是原点,并且数据都是正整数,所以肯定能保证
51                 //这是一个向下凸包;
52             }
53             tail++;
54             q[tail]=i;
55         }
56         printf("%d\n",f[n]);
57     }
58     return 0;
59 }

 

posted @ 2019-11-18 16:37  古比  阅读(196)  评论(0编辑  收藏  举报