链接:http://poj.org/problem?id=3612
题意:
有N根柱子, 高度确定, 现在要使它们连接起来,划分为相邻的柱子的高度差 h *C, 还可以加高度, 花费为所加高度 x 的平方;求最小花费;
思路:
朴素的想法: 用dp[i][j] 代表第 i 根柱子高度为 j 时的最小花费, 那么 dp[i][j] = dp[i-1][k] + abs( j-k ) * C + (j-a[i])^2;
复杂度为 10^5*10^2*10^2 = 10^9 TLE 无压力 ;
再来看上面的式子, 去绝对值得到 dp[i][j]=dp[i][k]+(j-k)*C+j-a[i]^2 = dp[i][k]-K*C+j*C+( j-a[i] )^2; ( j>k )
dp[i][j]=dp[i][k]+(k-j)*C+j-a[i]^2 = dp[i][k]+K*C-j*C+( j-a[i] )^2; ( j<K)
对于 j 来说 j*C+( j-a[i] )^2 为定值 所以我们只要考虑 dp[i][k]-K*C ( j>K ) 和 dp[i][k] + K*C (j<K)
我们可以用另外两个数组分别保存他们的最优解, 即可得到 dp 的最优解 ;
low[i-1][k]=dp[i - 1][k] - c * k ; high[i - 1][k] = dp[i - 1][k] + c * k ;
对于相同的 i, 它们都只与当前的k有关, 且可以互相转化,所以可以只开一维;
则 : dp[i][j] = min(low[i - 1][k] + c * j + (j - a[i]) ^ 2) , high[i - 1][k] - c * j + (j - a[i]) ^ 2));
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 using namespace std; 5 int dp[102],low[102],high[102]; 6 const int inf=1<<30; 7 8 int main() 9 { 10 int n,c; 11 while(scanf("%d%d",&n,&c)!=EOF){ 12 int h; 13 memset(low,0x3f,sizeof(low)); 14 memset(high,0x3f,sizeof(high)); 15 16 for(int i=1; i<=n; i++){ 17 scanf("%d",&h); 18 if( i==1 ){ 19 for(int i=0; i<h; i++) 20 dp[i]=inf; 21 for(int i=h; i<=100; i++) 22 dp[i]=(i-h)*(i-h); 23 } 24 else{ 25 memset(dp,0x3f,sizeof(dp)); 26 for(int j=h; j<=100; j++) 27 dp[j]=min(j*c+(h-j)*(h-j)+low[j],(h-j)*(h-j)-j*c+high[j]); 28 } 29 30 low[0]=dp[0]; 31 for(int i=1; i<=100; i++) 32 low[i]=min(dp[i]-i*c,low[i-1]); 33 high[100]=dp[100]+100*c; 34 for(int i=99; i>=0; i--) 35 high[i]=min(dp[i]+i*c,high[i+1]); 36 } 37 int ans=inf; 38 for(int i=0;i<=100;i++) 39 ans=min(ans,dp[i]); 40 printf("%d\n",ans); 41 } 42 return 0; 43 }