斜率优化DP

题意:
将含有N个元素的一个集合分成M个子集,使得每个子集的最大值与最小值平方差的和最小。

可以想到贪心将元素从小到大排序,很快可以得出dp[i][j]-前i个子集分j个元素的最小花费,
dp方程  dp[i][j]=dp[i-1][k]+(a[j]-a[k+1]);但是需要三重循环,时间复杂度接受不了,所以需要优化,这题斜率优化和四边形不等式都可以,先看斜率优化。
设k1<k2<j,如果k1比k2优,则有dp[i-1][k1]+(a[j]-a[k1+1])^2<dp[i-1][k2]+(a[j]-a[k2+1])^2;
化简得 ( dp[i-1][k1]+a[k1+1]^2-(dp[i-1][k2]+a[k2+1]^2) )/(a[k1+1]-a[k2+1])<=2a[j];
————————————————
版权声明:本文为CSDN博主「utobe67」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/tobewhatyouwanttobe/article/details/36209591

下面贴代码 代码自己写的

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<string.h>
 4 using namespace std;
 5 const int maxn=1e4+10;
 6 const int maxm=5e3+10;
 7 int a[maxn];
 8 int dp[maxn][maxm]; //dp[i][j]:前i个数分为j个集合的最小值;
 9 int q[maxn];
10 int up(int x,int y,int base)
11 {
12     return dp[y][base]-dp[x][base]+a[y+1]*a[y+1]-a[x+1]*a[x+1];
13 }
14 int down(int x,int y)
15 {
16     return a[y+1]-a[x+1];
17 }
18 void init()
19 {
20     memset(dp,0,sizeof(dp));  //这波初始化好像没什么必要;
21 }
22 int main()
23 {
24     int T,i,j;
25     scanf("%d",&T);
26     int cot=1;
27     while(T--){
28         init();
29         int n,m;
30         scanf("%d%d",&n,&m);
31         for(i=1;i<=n;i++) scanf("%d",&a[i]);
32         printf("Case %d: ",cot);
33         cot++;
34         sort(a+1,a+1+n);  //从小到大排序;
35         for(i=1;i<=n;i++) dp[i][1]=(a[i]-a[1])*(a[i]-a[1]);  //一个集合的情况下先列举;
36         for(j=2;j<=m;j++){
37             int head=0,tail=0;
38             q[++tail]=j-1;  //一个区间要分出j个集合,在这里进行新一轮的状态转移的时候,
39                            //新的状态是一个集合,那么旧的状态就是j-1个集合
40                         //要组成j-1个集合,至少j-1个数,所以就把这个数先放进去;
41             for(i=j;i<=n;i++){   
42                 while(head<tail){  
43                     int t1=q[head];   
44                     int t2=q[head+1];  
45                     int temp=2*a[i];  
46                     if(up(t1,t2,j-1)<=down(t1,t2)*temp) head++;
47                     else break;
48                 }
49                 int t=q[head];
50                 dp[i][j]=dp[t][j-1]+(a[i]-a[t+1])*(a[i]-a[t+1]);
51                 while(head<tail){
52                     int t1=q[tail-1];
53                     int t2=q[tail];
54                     if(up(t2,i,j-1)*down(t1,t2)<=up(t1,t2,j-1)*down(t2,i)) tail--;
55                     else break;
56                 }
57                 tail++;
58                 q[tail]=i;
59             }
60         }
61         printf("%d\n",dp[n][m]);
62     }
63     return 0;
64 }

 

 
posted @ 2019-11-18 20:28  古比  阅读(157)  评论(0编辑  收藏  举报