给定n个大小不等的圆c1,c2,…,cn,现要将这n个圆排进一个矩形框中,且要求各圆与矩形框的底边相切。圆排列问题要求从n个圆的所有排列中找出有最小长度的圆排列。例如,当n=3,且所给的3个圆的半径分别为1,1,2时,这3个圆的最小长度的圆排列如图所示。其最小长度为。
#coding:utf-8
import sys
import math
import copy
cc = []
def bianchang(a, l, c):
if l == 0:
return 2 * a
else:
b = (a + c) ** 2 - (abs(a - c)) ** 2
return l - c + math.sqrt(b) + a
def compute(d, a, n, l, c): #d表示输入半径的列表,a表示第几个半径,n表示半径的总共个数,l表示上一次计算的边长,c表示上一次圆的半径
d1 = copy.deepcopy(d) #对d进行深拷贝
if a == n: #当计算到第n个半径时,将结果保存在列表cc中
global cc
cc.append(l)
#print cc
else:
for i in range(0, len(d1)):
if d1[i] != 0:
t = bianchang(d1[i], l, c) #当加入新的圆时,计算加入后的边长
w = d1[i]
d1[i] = 0 #该半径计算完成后,将其置为0,标志已经计算结束
compute(d1, a + 1, n, t, w)
d1[i] = w #再将该半径的值恢复,方便下一次的回溯计算
if __name__ == '__main__':
n = input() #n表示输入半径的个数
d = sys.stdin.readline().strip().split(' ') #d表示输入的半径,以空格进行分割
d = map(int, d)
compute(d, 0, n, 0, 0) #回溯算法
print min(cc)