1、这道题的难点就在于“圆”,圆会相切,圆有大有小,所以要考虑各种情况。
2、用回溯法,每次添加一个新圆的时候,这个新圆可能与前面任一个圆重叠,所以要全部扫描一遍,求出位于最右边的圆心位置,存入b数组。
3、还要小心两端,每次添加新圆的时候,还要考虑是否和最左边的板重叠,而在计算最右边的板的位置的时候,要注意任何一个圆都可能与之相切。
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
double ans;
int vis[10],m;
double a[10],b[10];
int c[10];
void dfs(int depth,int num){
if(depth==m-1){
double temp=0;
for(int i=0;i<m;i++){
if(a[c[i]]+b[i]>temp)
temp=a[c[i]]+b[i];
}
if(temp<ans) ans=temp;
return;
}
for(int i=0;i<m;i++)
if(!vis[i]){
vis[i]=1;
double max=0;
for(int j=0;j<=depth;j++){
if(2*sqrt(a[i]*a[c[j]])+b[j]>max)
max=2*sqrt(a[i]*a[c[j]])+b[j];
}
if(a[i]>max) max=a[i];
b[depth+1]=max;
c[depth+1]=i;
dfs(depth+1,i);
vis[i]=0;
}
return;
}
int main(){
int n;
scanf("%d",&n);
while(n--){
scanf("%d",&m);
ans=0;
for(int i=0;i<m;i++){
scanf("%lf",&a[i]);
ans+=2*a[i];
}
memset(vis,0,sizeof(vis));
for(int i=0;i<m;i++){
vis[i]=1;
b[0]=a[i];
c[0]=i;
dfs(0,i);
vis[i]=0;
}
printf("%.3lf\n",ans);
}
return 0;
}