HDU 2829 Lawrence(斜率优化DP O(n^2))

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2829

题目大意:有一段铁路有n个站,每个站可以往其他站运送粮草,现在要炸掉m条路使得粮草补给最小,粮草补给的公式是将每个站能收到的粮草的总和。

4----5-----1-----2

粮草总和为4*5 + 4*1 + 4*2 + 5*1 + 5*2 + 1*2 = 49.

4----5       1-----2

粮草总和为4*5 + 1*2 = 22. 

4      5-----1------2

粮草总和为5*1 + 5*2 + 1*2 = 17.

解题思路:数组dp[i][j]表示第i个位置炸成j段的最小价值,cost[i][j]表示i~j这段的价值,则得到状态转移方程:

     dp[i][j]=min{dp[k][j-1]+cost[k+1][i]}.(k<i),复杂度为O(n^3)显然会超时

     易得cost[1][i]=cost[1][k]+cost[k+1][i]+sum[k]*(sum[i]-sum[k])

     则cost[k+1][i]=cost[1][i]-cost[1][k]+sum[k]^2-sum[k]*sum[i].

     使用cost[i]表示cost[1][i]得,dp[i][j]=min{dp[k][j-1]+cost[i]-cost[k]+sum[k]^2-sum[k]*sum[i]}.   

     可以得出 y=dp[k][j-1]-cost[1][k]+sum[k]^2

     x=sum[k].

     斜率sum[i]。

     用斜率优化,将复杂度降为O(n^2)即可。

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 using namespace std;
 5 const int N=1e3+5;
 6 int dp[N][N],sum[N],cost[N],q[N],head,tail;
 7 
 8 //yj-yk/xj-xk 
 9 double Slope(int m,int k,int j){
10     return double(dp[j][m-1]+sum[j]*sum[j]-cost[j]-dp[k][m-1]-sum[k]*sum[k]+cost[k])/(sum[j]-sum[k]);
11 }
12 
13 //dp[i][j]=min{dp[k][j-1]+cost[i]-cost[k]-sum[k]*(sum[i]-sum[k])} 
14 int getDP(int i,int j,int k){
15     return dp[k][j-1]+cost[i]-cost[k]-sum[k]*(sum[i]-sum[k]);
16 }
17 
18 int main(){
19     int n,m;
20     while(~scanf("%d%d",&n,&m)){
21         if(m==0&&n==0)
22             break;
23         memset(cost,0,sizeof(cost));
24         sum[0]=0;
25         for(int i=1;i<=n;i++){
26             scanf("%d",&sum[i]);
27             sum[i]+=sum[i-1];
28         }
29         for(int i=1;i<=n;i++){
30             for(int j=1;j<i;j++){
31                 cost[i]+=(sum[j]-sum[j-1])*(sum[i]-sum[j]);
32             }
33             dp[i][1]=cost[i];
34         }
35         for(int j=2;j<=m+1;j++){
36             head=tail=0;
37             q[tail++]=j-1;
38             for(int i=j;i<=n;i++){
39                 while(head+1<tail&&Slope(j,q[head],q[head+1])<=sum[i]){            
40                     head++;
41                 }
42                 dp[i][j]=getDP(i,j,q[head]);
43                 while(head+1<tail&&Slope(j,q[tail-2],q[tail-1])>=Slope(j,q[tail-1],i)){
44                     tail--;
45                 }
46                 q[tail++]=i;        
47             }
48         }
49         printf("%d\n",dp[n][m+1]);
50     }
51     return 0;
52 }

 

     

posted @ 2017-11-10 15:52  Yeader  阅读(217)  评论(0编辑  收藏  举报