题目的意思就是给你几个圆,输入的的半径,排过去长度最小是多少。
先是全排列,得到所有的顺序,然后每个顺序计算长度。
计算长度的方法就是先算出第一个圆的圆心位置(也就是第一个圆的半径) ,然后第二个圆的圆心位置 和第一个圆的圆心位置 相差两圆的半径相乘开更乘以2。当然也可以用两圆半径和的平方 + 两圆半径差的平方 再开更。得到距离在加上第一个个圆的圆心位置就得到第二个的了。算到第n个圆圆心位置。
但要注意以下几点:
1.第n个圆的圆心位置,不一定就是和前一个圆计算得来的。有可能第一个圆很大,第二个圆很小,第三个圆和第一个圆相切,而不碰到第二个圆,所以每个圆要和所有之前的 圆进行计算,取最大值。
2.如果第一个圆很小,第二个圆很大,计算完第二个的圆心位置可能会比半径小,也就是超过了左边边界,这时候它的圆心位置应该变成它的半径。
3.最后就是注意,并不是最后一个圆的圆心位置加上半径,就是所求的长度,有可能前一个特别大,最后一个很小,根本没碰到边界,所以要计算每个圆的圆心位置加半径,取 最大的,才是最后结果。
AC代码:
#include<iostream>
#include<cmath>
#include<algorithm>
#include<string.h>
#include<stdio.h>
using namespace std;
double circle[10];
double center[10];
int num;
double m;
double m2;
double fina;
void search(int pos) {
if(pos == num)
return ;
double temp;
m = 0;
for (int i = 0 ; i < pos ;i++) {
temp = 2 * sqrt (circle[i] * circle[pos] );
temp += center[i];
if (temp - circle[pos] < 0)
temp = circle[pos];
if (temp > m) {
m = temp;
}
}
center[pos] = m;
if (center[pos] + circle[pos] > m2)
m2 = center[pos] + circle[pos];
search(pos + 1);
}
void cul () {
do {
m2 = circle[0] * 2;
center[0]= circle[0];
search(1);
if (m2 < fina) {
fina = m2;
}
}while(next_permutation(circle , circle + num));
}
int main () {
int t;
cin >> t;
while (t--) {
cin >> num;
for (int i = 0 ; i < num ; i++) {
cin >> circle[i];
}
sort(circle , circle + num);
fina = 9999999999999;
if(num != 1)
cul();
else
fina = circle[0] * 2;
printf("%.3lf\n", fina);
}
}