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

注:参考的是这篇文章
https://blog.csdn.net/qq_37373250/article/details/81477394?ops_request_misc=&request_id=&biz_id=102&utm_term=%E5%9C%86%E6%8E%92%E5%88%97%E9%97%AE%E9%A2%98&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduweb~default-0-81477394
这篇对这个问题解释很赞
下面这篇是我对上面这篇文章的笔记吧。。。,随便瞅瞅吧,算是给自己看的,写的是自己理解的关键点。
上面这篇文章讲得很有条理,也很细容易懂。
理解这篇文章花了近两个小时,算法果然是很难学的东西呐,/(ㄒoㄒ)/~~。

1.问题

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

2.解析

n个圆放在一条水平线上,用一个矩形框将所有圆给框在一起,四条边都有圆与其相切。求这个矩形框的水平长度最小,也就是圆排列问题的解

分析:
n个圆不同的排列会造成最后的排列长度不同,那么利用回溯算法,计算每个排列的长度,找出最小的即可。

这个篇章思想:
① 每个圆的圆心的横坐标存储在X数组中,X[1]代表第一个圆的圆心横坐标,即为0。
② 每个圆的半径存储在R数组中。
③ 所有排列中,最左边的第一个圆的圆心坐标为0,即为X轴的原点
④ 利用a2+b2=c2,两个圆的圆心横坐标的距离 = sqrt((r22+r12)-( r22-r12))
这四个可以组成一个函数计算每个圆的横坐标-center(int)。

① 将第一个圆的圆心作为中心线,左边部分+上右边部分为圆排列长度
② 如果X[i]-R[i] < left ,left = X[i]-R[i];
③ 如果X[i]+R[i] < right, right = X[i]+R[i];
④ 最后 right-left= 圆排列长度,因为left为负数,
这四个可以组成一个函数计算整个圆排列的长度,而且能概括所有的情况—compute()。
比如:
第一种:

第二种

第三种

再然后就是回溯算法思想:
① 这个算法是递归思想,第一个圆的位置有n种,第二个圆的位置有n-1种,但每个圆都会尝试每一种可能性:
比如这种写法:
递归函数(){
for i to n
if{}
else{
安排这个位置圆的种类
再调用这个递归函数并且种类数量-1;
}
}
如果用笔写一下,跟着算法走一下,发现是一棵树,

上面这篇文章,我认为最巧的地方就是这个地方了:

这个算法会造成这棵树这个样子

这个算法用一个数组,通过交换改变数组中的,完成了每一层圆的种类选择不同的结果
第一个位置,即第一行,t为1时,j=1时整个R数组为ABC,j=2时,整个R数组为BAC,1、2两个位置交换,j=3时,1、3两个位置交换,整个R数组为CAB,
第二层同理,感觉不可思议,因为我的脑袋完全不能容纳所有的思考空间,只能通过一步一步推,得知这个结果。

我自己设想的类似效果,是这样的,每一层都遍历这个R数组,但是这个R数组是一个结构体,里面有两个变量分别是半径长,与是否被选中放置这个位置的标志flag变量,被选中则flag = 1,判断时候只用加个!flag判断那些圆是未被选中的即可,我感觉这个更好理解

3. 设计

C++伪代码

backtrack(int t)
{
   if(t>n) 计算排列长度
  else
   for(int j=t;j<=n;j++)
    {
        swap(r[t],r[j]);//确定当前第t个圆的半径,或者说,对第t个圆进行了选择
       求出第t个圆选入后,排列的长度,可称之为当前排列长度
       找到界限条件,如果满足条件
         {
            入选所选的第t个圆;
            开始深入到第t+1个圆,即backtrack(t+1)
         }
      swap(r[t],r[j]); //恢复现场
     }   
}
画图可知最后算法运行流程是一颗

实验图片~:

4. 分析

根据这棵树 应该是O(n!)

5. 源代码地址

https://github.com/Lin02993/Algorithm-Analysis-and-Practice-on-the-job

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值