题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=5073
题目大意:
有n个行星,然后可以将其中的k个进行位移。n个行星会有一个中心位置,每个行星距离中心的距离是di。现在要移动k个行星,使得Σwi*di^2最小。其中wi是行星的质量,可以看成是1。
思路:
暴力模拟。从第一个位置开始,对n-k个行星进行位移,计算答案。然后再从第二个位置开始对后面的n-k个行星进行位移,如此往复,选取最小值。
代码:
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#define ll __int64
using namespace std;
int min(int a,int b)
{
return a<b?a:b;
}
int main()
{
ll T,n,k,i,j,a[50005],sum;
scanf("%I64d",&T);
while(T--)
{
scanf("%I64d%I64d",&n,&k);
for(i=1;i<=n;i++)
scanf("%I64d",&a[i]);
sort(a+1,a+1+n);
if(n==k)
{
printf("0.00000\n");
continue;
}
ll tot=0;
sum=0;
for(i=1;i<=n-k;i++)
{
sum+=a[i];
tot+=a[i]*a[i]; //将(a-b)^2展开变成a^2+b^2-2ab。计算出a^2和a的和。
}
double ave=(sum*1.0)/(n-k);
double mini=ave*ave*(n-k)-2*ave*sum+tot;
// printf("%.5f\n",mini);
for(i=2;i<=k+1;i++)
{
sum=sum-a[i-1]+a[n-k+i-1];
ave=(sum*1.0)/(n-k);
tot=tot-a[i-1]*a[i-1]+a[n-k+i-1]*a[n-k+i-1];
double temp=ave*ave*(n-k)-2*ave*sum+tot;
if(temp<mini)mini=temp;
}
printf("%.12f\n",mini);
}
return 0;
}