问题
圆排列问题:给定n个圆的半径序列,将它们放到矩形框中,各圆与矩形底边相切,求具有最小排列长度的圆排列。
解析
圆排列问题的解空间是一棵排列树。按照回溯法搜索排列树的算法框架,设开始时a=[r1,r2,……rn]是所给的n个圆的半径,则相应的排列树由a[1:n]的所有排列构成。
1、compute函数可以想象其中任意的一个圆无限大或无限小,无限大的话那其余的圆就可以统统忽略了。因为已知所有圆的x坐标和半径r,很容易求出每个圆的左右坐标,通过比较找出最小的左部坐标和最大的右部坐标,一减就是该圆排列的长度,然后把每次不同的排列长度相比较,找到更小的minlen就更新。
2、 center函数计算圆在当前圆排列中的横坐标,由x^2 = sqrt((r1+r2)2-(r1-r2)2)推导出x = 2sqrt(r1r2)。注意排在任意位置的圆与其前或后的任意一个圆都有可能相切的,如图所示。
3、back函数,这里用到的核心方法就是回溯法,回溯最重要的就是求出界限函数.按问题性质,可画出子集树或排列树。if(cx+r[t]+r[1]<minlen)的作用是剪枝,先判断当前层是否在范围内,是则继续搜索下一层,否则直接回溯。下图是不进行剪枝时,六种可能性都搜索一遍的过程。
设计
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cmath>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
double minlen, x[1010], r[1010];
int n