【BZOJ】1705: [Usaco2007 Nov]Telephone Wire 架设电话线

【题意】给定一排n根杆高度hi,一个常数C,杆升高x的代价为x^2,相邻两杆之间架设电话线代价为高度差*C,求总代价最小。

【算法】DP+辅助数组优化

【题解】令f[i][j]表示第i根杆高度为j的最小代价。

f[i][j]=min(f[i-1][k]+C*|j-k|+(a[i]-j)^2)。复杂度O(n*100*100)。

考虑优化方向是省略k这一维的枚举,故分离方程中和k无关的变量

f[i][j]=min(f[i-1][k]-C*k)+C*j+(a[i]-j)^2,k<=j

f[i][j]=min(f[i-1][k]+C*k)-C*j+(a[i]-j)^2,k>j

这样就可以用辅助数组优化了。

b[i][j]=min(f[i][k]-C*k),k<=j

c[i][j]=min(f[i][k]+C*k),k>=j

则方程转化为:

f[i][j]=min( b[i-1][j] + C*j , c[i-1][j+1] - C*j )+C*j+(a[i]-j)^2。

复杂度O(n*100)。

细节:

1.必须初始化f[1]。

2.是c[j+1],因为统计的时候是>=。

3.所有初始化为inf。

#include<cstdio>
int min(int a,int b){return a<b?a:b;}
const int maxn=100010,maxk=110,inf=0x3f3f3f3f;
int f[maxk],b[maxk],c[maxk],n,m,C,a[maxn];
int main(){
    scanf("%d%d",&n,&C);
    for(int i=1;i<=n;i++){scanf("%d",&a[i]);if(a[i]>m)m=a[i];}
    b[0]=c[m+1]=inf;
    for(int i=1;i<=n;i++){
        if(i==1)for(int j=1;j<=m;j++)if(j>=a[i])f[j]=(a[i]-j)*(a[i]-j);else f[j]=inf;
        else for(int j=1;j<=m;j++)if(j>=a[i])f[j]=min(b[j]+C*j,c[j+1]-C*j)+(a[i]-j)*(a[i]-j);else f[j]=inf;
        for(int j=1;j<=m;j++)b[j]=min(b[j-1],f[j]-C*j);
        for(int j=m;j>=1;j--)c[j]=min(c[j+1],f[j]+C*j);
    }
    int ans=inf;
    for(int i=1;i<=m;i++)ans=min(ans,f[i]);
    printf("%d",ans);
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/onioncyc/p/7665696.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值