1、问题
2、解析
第一个圆的圆心横坐标为0
定义x(k)数组算出排列第k个圆的圆心横坐标
minlen为最短的矩形的长度if(centerx+r[t]+r[1]<minlen)语句判断是否还要继续进行下去
bestr定义一个最优的圆的排序序列因为第K个圆不一定和第k-1个圆相切,如图:
所以要进行循环判断圆心横坐标选取最远的距离
可以得到排列树
3、设计
求圆心横坐标:
double center(int t) {//圆心坐标
double temp = 0;
//由于后面一个圆不一定与前一个圆相切,可能与前面的任一圆相切
for (int j = 1; j < t; j++) {
double xvalue = x[j] + 2.0 * sqrt(r[t]*r[j]);
if (xvalue > temp) {
//对于排列的第t个圆,距离最远的便是排列第t的圆的横坐标
temp = xvalue;
}
}
return temp;
//排列第一个的圆的圆心横坐标是0
}
回溯算法:
void backtrack(int t) {
if (t > n) {
compute();
}
else {
for (int j = t; j <= n; j++) {
swap(r[t], r[j]);
double centerx = center(t);//获取圆心横坐标
//如果某个圆加起来的序列长度比当前最小序列的长度还要小,则继续进行,否则结束
if (centerx + r[t] + r[1] < minlen) {
x[t] = centerx;
backtrack(t + 1);
}
swap(r[t],r[j]);
}
}
}
求矩阵的最短长度:
void compute() {
double low = 0, high = 0;//表示矩阵框的左右边界
for (int i = 1; i <= n; i++) {
if (x[i] - r[i] < low) {
low = x[i] - r[i];
}
if (x[i] + r[i] > high) {
high = x[i] + r[i];
}
}
if (high - low < minlen) {
minlen = high - low;
for (int i = 1; i <= n; i++) {
bestr[i] = r[i];
}
}
}
4、分析:
Backtrack函数需要O(n!)的时间复杂度,计算当前圆排列长度需要从头遍历到尾,需要O(n)计算时间,从而整个算法的时间复杂度为O((n+1)!)
5. 源码
源码地址:https://github.com/ACynj/circle.git