算法分析与设计实践-大作业-圆排列问题

圆排列问题

1.问题

给定n个圆的半径序列,将它们放到矩形框中,各圆与矩形底边相切,求具有最小排列长度的圆排列。

2.解析

圆排列问题的解空间是一棵排列树。按照回溯法搜索排列树的算法框架,设开始时a=[r1,r2,……rn]是所给的n个元的半径,则相应的排列树由a[1:n]的所有排列构成。
在这里插入图片描述

  1. 定义一个函数center()来计算圆在当前圆排列中的横坐标,
    在这里插入图片描述
    在这里插入图片描述
  2. 定义一个函数compute()来计算当前圆的排列长度,找到排列的最左端 if(x[i]-r[i]<left) left=x[i]-r[i]; 找到排列的最右端if(x[i]+r[i]>right)计算出最右端 right=x[i]+r[i]; right-left就可以得到圆排列的长度。
  3. 变量lenmin记录当前最小圆排列长度。数组r存储所有圆的半径。数组x则记录当前圆排列中各圆的圆心横坐标。
  4. 在递归算法Backtrack中,当k>n时,算法搜索至叶节点,得到新的圆排列方案。此时算法调用Compute计算当前圆排列的长度,适时更新当前最优值。当k<n时,当前扩展节点位于排列树的k-1层。此时算法选择下一个要排列的圆,并计算相应的下界函数,还可以加入操作,若当前圆k的坐标center+r[1]+r[k]>=最小圆排列长度,就不需要继续遍历这个序列了。

3.设计

void backtrack(int k){
    
     //查找圆排列
    if(k>n){
    
    //结束排列,计算排列长度 
        calLength();
        return ;
    }
    for(int i=k;i<=n;i++){
    
    
        swap(r[k],r[i]);
        double center=calCenter(k);//获取圆当前的横坐标
        if(center+r[1]+r[k]<minn){
    
    //剪枝操作 
        	x[k]=center;
        	backtrack(k+1);//向下继续搜索
		}
        swap(r[k],r[i]);//回溯
    }
}

4.分析

由于算法Backtrack在最坏情况下需要计算O(n!)次圆排列长度,每次计算需要O(n)计算时间,得出时间复杂度为O((n+1)!)
空间复杂度为O(n)

5.源码

https://github.com/lu-225/As-before/blob/master/2018212212124%20%E9%99%86%E5%AE%B6%E8%BE%89%20%E5%AE%9E%E8%B7%B5%E5%A4%A7%E4%BD%9C%E4%B8%9A/%E5%9C%86%E6%8E%92%E5%88%97%E9%97%AE%E9%A2%98.cpp

猜你喜欢

转载自blog.csdn.net/qq_43633353/article/details/106773495