暴力解法
8个圆 全排列 一个个判断
回溯 也是全排列的思想 但是在进行排列的时候取一个最小的 如果还没有排完就已经比最小的还大 那么后面的所有以此为基础的答案都可以舍去
不用判断
上面的大体思路是正确的 但是忽略了一个问题 那就是排列中两个相邻的圆一定相切吗? 答案是否定的
所以我们还需要考虑两个圆不相切的情况 那这样怎么才能确定当前圆应该放在哪个位置 可以想象到 放的当前圆一定是离原点最远 而且
还与前面的某一个圆相切 这样不难判断这一个圆的位置 直接枚举计算当前圆和前面每个园相切时圆的位置 保存离原点最远的一个
8个圆 全排列 一个个判断
回溯 也是全排列的思想 但是在进行排列的时候取一个最小的 如果还没有排完就已经比最小的还大 那么后面的所有以此为基础的答案都可以舍去
不用判断
上面的大体思路是正确的 但是忽略了一个问题 那就是排列中两个相邻的圆一定相切吗? 答案是否定的
所以我们还需要考虑两个圆不相切的情况 那这样怎么才能确定当前圆应该放在哪个位置 可以想象到 放的当前圆一定是离原点最远 而且
还与前面的某一个圆相切 这样不难判断这一个圆的位置 直接枚举计算当前圆和前面每个园相切时圆的位置 保存离原点最远的一个
保存每个圆的最左位置和最右位置 循环一遍找到位置最左 和位置最右 两个相减就是当前排列所需要盒子的宽度
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn = 10;
double Dis(double R,double r)
{
return 2*sqrt(R*r);
}
struct Point
{
double x,y,l,r;
};
int main()
{
#ifdef LOCAL
freopen("in.txt","r",stdin);
#endif // LOCAL
int n,m;
scanf("%d",&n);
while(n--)
{
scanf("%d",&m);
double R[m];
for(int i = 0; i < m; i++)
scanf("%lf",&R[i]);
double MIN = 0x3f3f3f3f,t;
sort(R,R+m);
do
{
struct Point O,P[m];
double Left_len = 0x3f3f3f3f ,Right_len = -0x3f3f3f3f;
O.x = O.y = 0;
P[0].x = P[0].y = R[0];
P[0].l = 0;
P[0].r = 2*R[0];
for(int i = 1; i < m; i++)
{
double t = -0x3f3f3f3f; /// 不用判断y的位置 只需要判断x距离原点的位置即可
for(int j = 0; j < i; j++)
{
double temp = Dis(R[j],R[i]);
if(t < (temp + P[j].x)) t = temp + P[j].x;
}
P[i].x = t;
P[i].y = R[i];
P[i].l = P[i].x - R[i];
P[i].r = P[i].x + R[i];
}
for(int i = 0; i < m; i++)
{
if(Left_len > P[i].l) Left_len = P[i].l;
if(Right_len < P[i].r) Right_len = P[i].r;
}
if(MIN > (Right_len - Left_len)) MIN = Right_len - Left_len;
}while(next_permutation(R,R+m));
printf("%.3lf\n",MIN);
}
return 0;
}