想到可能存在两个半径很大的圆相切,中间夹着很多小的圆(这样单纯的全排列只判断相邻两圆的话就可能出现圆圆相交的情况),这样就需要加为每个已经判断过的圆加个坐标,对于正在判断的圆,与前面所有判断是否相交,若相交以这两个圆为相邻圆,求当前圆坐标。
#include <iostream>
#include <cstring>
#include<cstdio>
#include<cstdlib>
#include <string>
#include<algorithm>
#include<cmath>
//#define MARK -2147483647
using namespace std;
double cir[10];int pai[10]={0,1,2,3,4,5,6,7,8,9}; int m;double ans=0;
struct yuanxin
{
double x,y;
};
double qiulong( )
{ yuanxin yuan[10];
double ll =0;
int i;
yuan[0].x=0.0;yuan[0].y=cir[pai[0]];
for(i=0;i<m-1;++i)
{ double llshi=ll;
//cout<<cir[pai[i]]<<cir[pai[i+1]]<<endl;
llshi=llshi+sqrt((cir[pai[i]]+cir[pai[i+1]])*(cir[pai[i]]+cir[pai[i+1]])-(cir[pai[i]]-cir[pai[i+1]])*(cir[pai[i]]-cir[pai[i+1]]));
//cout<<i<<"e"<<llshi<<endl;
yuan[i+1].x=llshi;yuan[i+1].y=cir[pai[i+1]];
for(int ii=i-1;ii>=0;--ii)
{
double bil=sqrt((yuan[ii].x-yuan[i+1].x)*(yuan[ii].x-yuan[i+1].x)+(yuan[ii].y-yuan[i+1].y)*(yuan[ii].y-yuan[i+1].y));
if(bil-(cir[pai[ii]]+cir[pai[i+1]])<-(1e-6))
{ll=yuan[ii].x+sqrt((cir[pai[ii]]+cir[pai[i+1]])*(cir[pai[ii]]+cir[pai[i+1]])-(cir[pai[ii]]-cir[pai[i+1]])*(cir[pai[ii]]-cir[pai[i+1]]));llshi=ll;yuan[i+1].x=llshi; }
}//cout<<i<<"e"<<llshi<<endl;
ll=llshi;
}
ll=ll+cir[pai[m-1]];
for(int ii=m-2;ii>=0;--ii)
{
if(ll-(yuan[ii].x+cir[pai[ii]])<-(1e-6))ll=yuan[ii].x+cir[pai[ii]];
}
double bii=-cir[pai[0]];
for(int ii=m-1;ii>=0;--ii)
{
//if(ll-(yuan[ii].x+cir[ii])<-(1e-6))ll=yuan[ii].x+cir[ii];
if(bii-(yuan[ii].x-cir[pai[ii]])>1e-6) bii=yuan[ii].x-cir[pai[ii]];
}
return ll-bii;
}
int main()
{
// freopen("in.txt","r",stdin);
int n;scanf("%d",&n);
while(n--)
{
scanf("%d",&m);
int i;ans=0;
for(i=0;i<m;++i)
{
scanf("%lf",&cir[i]);
ans+=2*cir[i];
}
do
{
double ll=qiulong();
if((ll-ans)<-(1e-6)) ans=ll;
}while(next_permutation(pai,pai+m));
printf("%.3lf\n",ans);
}
return 0 ;
}