这题刚开始以为就是简单的贪心,后来发现当两个球的半径差距很大时,两球的距离就不再是2*sqrt(r1*r2)了。
这样一下就没有思路了,在网上搜了下题解,才知道要记录摆放的球的球心坐标,然后通过之前摆放过的球的球心坐标更新之后摆放的球的球心坐标,最后求所摆放的球所占据的长度。
注意到球的数量<=8,所以就可以直接枚举全排列。代码写的比较搓……勉强水过了。
#include <iostream>
#include <fstream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
double r[10];
int p[10];
double x[10];
int main()
{
freopen("in.txt","r",stdin);
int T;
cin>>T;
while(T--)
{
int n;
cin>>n;
for(int i=0;i<n;i++)
{
cin>>r[i];
p[i]=i;
}
double ans=0;
double d=0;
x[0]=r[0];
for(int i=1;i<n;i++)
{
double tmp=0;
for(int j=0;j<i;j++)
tmp=max(tmp,x[j]+2*sqrt(r[j]*r[i]));
x[i]=tmp;
}
for(int i=0;i<n;i++) d=min(d,x[i]-r[i]);
for(int i=0;i<n;i++) ans=max(ans,x[i]+r[i]-d);
while(next_permutation(p,p+n))
{
x[p[0]]=r[p[0]];
double tmp=0;
for(int i=1;i<n;i++)
{
double t=0;
for(int j=0;j<i;j++)
t=max(t,x[p[j]]+2*sqrt(r[p[j]]*r[p[i]]));
x[p[i]]=t;
}
d=0;
for(int i=0;i<n;i++) d=min(d,x[p[i]]-r[p[i]]);
for(int i=0;i<n;i++) tmp=max(tmp,x[p[i]]+r[p[i]]-d);
ans=min(ans,tmp);
}
printf("%.3f\n",ans);
}
return 0;
}