您的位置:首页 > 其它

HihoCoder1621 : 超市规划(四边形DP优化)()

2017-11-09 19:15 295 查看

超市规划

时间限制:10000ms
单点时限:1000ms
内存限制:256MB

描述

小Hi居住的城市的中轴线恰好是一条马路。沿着这条马路一共坐落有N个居民小区,其中第i个小区距离马路一端的距离是Ai。

现在市政厅决定在这条马路沿线修建K个超市(可以修建在任意实数位置),并且定义“不方便指数”是所有小区与最近的超市距离的平方之和。

当然市政厅希望“不方便指数”越小越好,请求出该指数的最小值。

输入

第一行包含两个整数N和K。

以下N行每行包含一个整数Ai。

对于50%的数据,1 ≤ N, K ≤ 100

对于100%的数据,1 ≤ N, K ≤ 2000 0 ≤ Ai ≤ 100000

输出

一个实数代表指数的最小值,保留3位小数。

样例输入
4 2
1
2
3
4

样例输出
1.000


有O(n^3)的解法,先知道两个结论:

1,i-j的点中找一个点,使得它到其他点的距离和最小,则这个点可以是下标为中值的点(也有可能一条线段,但是这个点再这条线段上,也满足),即x0=x[(i+j)/2];可以用反证法来证明。

2,i-j的线段上找一个点,使得它到其他点的距离平方的和最小,则这个点是几何中点,即x0=(xi+..xj)/(j-i+1);可以求偏导数来证明。

由2结论,我们得到如下代码:

其中c[i][j]是i到j中有一个超市时的最优解

则有O(n^3):

for(i=1;i<=n;i++)
for(j=i+1;j<=n;j++){
double mid=(sum[j]-sum[i-1])/(j-i+1);
for(k=i;k<=j;j++){
c[i][j]+=(a[i]-mid)*(a[i]-mid);
}
}


化简:c[i][j]=Σa[i]*a[i]+mid*mid-2*mid*a[i],则有O(n^2):

for(i=1;i<=n;i++)
for(j=i+1;j<=n;j++){
double mid=(suma[j]-suma[i-1])/(j-i+1);
c[i][j]=(summ[j]-summ[i-1])+(j-i+1)*mid*mid-2*mid*(suma[j]-suma[i-1]);
}


dp[i][j]表示前j个点有i个超市的最优解,则有O(nnk):

for(i=1;i<=n;i++) dp[1][i]=c[1][i];
for(i=2;i<=m;i++){
s[i][n+1]=n;
for(j=n;j>=1;j--){
for(k=1;k<=j;k++)
if(dp[i][j]>dp[i-1][k]+c[k+1][j]){
s[i][j]=k;
dp[i][j]=dp[i-1][k]+c[k+1][j];
}
}
}


四边形不等式优化:则有O(nk);

for(i=1;i<=n;i++) dp[1][i]=c[1][i];
for(i=2;i<=m;i++){
s[i][n+1]=n;
for(j=n;j>=1;j--){
for(k=s[i-1][j];k<=s[i][j+1];k++)
if(dp[i][j]>dp[i-1][k]+c[k+1][j]){
s[i][j]=k;
dp[i][j]=dp[i-1][k]+c[k+1][j];
}
}
}


所以O(n^2)就okey辣,鸡冻!

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=2010;
const double inf=100000000000000000;
double dp[maxn][maxn],c[maxn][maxn];
double a[maxn],suma[maxn],summ[maxn],s[maxn][maxn];
int main()
{
int n,i,j,k,m;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++) {
scanf("%lf",&a[i]);
suma[i]=suma[i-1]+a[i];
summ[i]=summ[i-1]+a[i]*a[i];
}
sort(a+1,a+n+1);
for(i=1;i<=n;i++) {
suma[i]=suma[i-1]+a[i];
summ[i]=summ[i-1]+a[i]*a[i];
}
for(i=1;i<=n;i++) for(j=i+1;j<=n;j++){ double mid=(suma[j]-suma[i-1])/(j-i+1); c[i][j]=(summ[j]-summ[i-1])+(j-i+1)*mid*mid-2*mid*(suma[j]-suma[i-1]); }
for(j=1;j<=m;j++)
for(i=1;i<=n;i++)
dp[j][i]=inf;
for(i=1;i<=n;i++) dp[1][i]=c[1][i];
for(i=2;i<=m;i++){
s[i][n+1]=n;
for(j=n;j>=1;j--){
for(k=s[i-1][j];k<=s[i][j+1];k++)
if(dp[i][j]>dp[i-1][k]+c[k+1][j]){
s[i][j]=k;
dp[i][j]=dp[i-1][k]+c[k+1][j];
}
}
}
printf("%.3lf\n",dp[m]
);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: