图文并茂详尽剖析圆排列问题

article/2025/9/20 20:36:41

 参考资料

  1. https://blog.csdn.net/liufeng_king/article/details/8890603
  2. https://blog.csdn.net/qq_32400847/article/details/51474105
  3. https://blog.csdn.net/yzmck/article/details/4302554 原理解释的很赞
  4. http://www.doc88.com/p-079198350775.html 
  5. http://www.docin.com/p-802993408.html 看算法效率部分

问题描述

     给定n个大小不等的圆c1,c2,…,cn,现要将这n个圆排进一个矩形框中,且要求各圆与矩形框的底边相切。圆排列问题要求从n个圆的所有排列中找出有最小长度的圆排列。例如,当n=3,且所给的3个圆的半径分别为1,1,2时,这3个圆的最小长度的圆排列如图所示。其最小长度为

     问题大方向分析

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

   1. center计算圆在当前圆排列中的横坐标,由x^2 = sqrt((r1+r2)^2-(r1-r2)^2)推导出x = 2*sqrt(r1*r2)。

   2.Compute计算当前圆排列的长度。变量lenmin记录当前最小圆排列长度。数组r存储所有圆的半径。数组x则记录当前圆排列中各圆的圆心横坐标。

    3. 在递归算法Backtrack中,当i>n时,算法搜索至叶节点,得到新的圆排列方案。此时算法调用Compute计算当前圆排列的长度,适时更新当前最优值。当i<n时,当前扩展节点位于排列树的i-1层。此时算法选择下一个要排列的圆,并计算相应的下界函数。

 

代码

#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;const int N=4;
double minlen=10000,x[N],r[N];//分别为最小圆排列长度,每个圆心横坐标,每个圆半径
double bestr[N];//最小圆排列的半径顺序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]);//不是r[j],是x[j],要被自己蠢哭了if(xvalue>temp)temp=xvalue;}return temp;
}
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];}
}
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]);}}
}
int main()
{r[1]=1,r[2]=1,r[3]=2;cout<<"每个圆的半径分别为:";for(int i=1;i<N;++i)cout<<r[i]<<' ';cout<<endl;backtrack(1);cout<<"最小圆排列长度为:"<<minlen<<endl;cout<<"最优圆排列的顺序对应的半径分别为:";for(int i=1;i<N;++i)cout<<bestr[i]<<' ';cout<<endl;return 0;
}

详解上诉代码

定义数组那几个就不讲了,看看注释就行了。下面来重点讲解一下三个功能函数。

1.首先是center函数,center计算圆在当前圆排列中的横坐标,由x^2 = sqrt((r1+r2)^2-(r1-r2)^2)推导出x = 2*sqrt(r1*r2),这个很容易理解吧。下面有人就会有疑惑了,为啥要把计算圆心坐标的公式放在一个for循环里面呢,我们很容易会有一个先入为主的思想,那就是后一个圆必然与排在它前一个位置的圆相切,其实排在任意位置的圆与其前或后的任意一个圆都有可能相切的,画个图就很清晰了。

大致就是这个意思,只要大小合适,目标圆就有可能与排列中的任意一个圆相切,搞明白了这个问题,那让我们顺着计算机的思维继续往下走,假设我们现在要求x[3]的坐标,只能从前往后的一一比较(此时x[1]和x[2]是已知的),先得到x[1]+a的值(即x[3]的可能坐标),再得到x[2]+b的值(与上一次的可能值相比较,若距离更大则更新,否则不做处理),后面依次类推。

有人可能会问为啥x[2]+b不能作为x[3]的值?很简单,圆2与圆3不相切,得到的b比实际的大,结果就偏大了。

友情提醒:for(int j=1;j<t;++j),因为for循环在初始化后是紧接着进行判断的,故当t=1时,j<1不成立直接跳过本次循环,直接返回temp=0,

故x[1]=0.

2.接下来说下backtrack函数,这里用到的核心方法就是回溯法,回溯法 最重要的就是求出界限函数.按问题性质,可画出子集树或排列树.

if(centerx+r[t]+r[1]<minlen)的作用是剪枝,先判断当前层是否在范围内,是则继续搜索下一层,否则直接回溯。下图是不进行剪枝时,六种可能性都搜索一遍的过程。

3.最后我们来解释一下compute函数,这个其实弄明白了上面的相切的概念,这就so easy 了,夸张一点,我们可以想象其中任意的一个圆无限大或无限小,无限大的话那其余的圆就可以统统忽略了。因为已知所有圆的x[]和r[],很容易求出每个圆的左右坐标,通过比较找出最小的左部坐标和最大的右部坐标,一减就是该圆排列的长度,然后把每次不同的排列长度相比较,找到更小的minlen就更新。

代码运行结果


http://chatgpt.dhexx.cn/article/lgliG3cl.shtml

相关文章

圆排列问题详解(原理+代码)

问题描述 给定n个大小不等的圆c1,c2,…,cn&#xff0c;现要将这n个圆排进一个矩形框中&#xff0c;且要求各圆与矩形框的底边相切。圆排列问题要求从n个圆的所有排列中找出有最小长度的圆排列。 问题分析 圆排列问题的解空间是一棵排列树&#xff0c;我们用回溯法在整个排列…

java字节序、主机字节序和网络字节序扫盲贴

java程序员是幸福&#xff0c;因为相对于C/C的不跨平台&#xff0c;JVM为我们屏蔽了大量的底层细节和复杂性&#xff0c;让我们能够将精力放在实现特定的业务逻辑上&#xff0c;所以使用java开发项目效率是比较高的。同时java程序员是悲哀的&#xff0c;就是因为JVM屏蔽了很多技…

字节序、位序

字节序 字节序&#xff0c;又称端序、尾序&#xff0c;英文单词为Endian&#xff0c;该单词来源于于乔纳森斯威夫特的小说《格列佛游记》&#xff0c;小说中的小人国因为吃鸡蛋的问题而内战&#xff0c;战争开始是由于以下的原因&#xff1a;我们大家都认为&#xff0c;吃鸡蛋前…

字节序的详细讲解

字节序 1、字节序的特点2、字节序转换函数2.1、htonl函数 发 将主机字节序的IP地址 转换成网络字节序的IP地址2.2、ntohl函数 收 将网络字节序的IP地址3.3、htons函数 发 将主机字节序的端口 转换成 网络字节序的端口3.4、ntohs函数 收 将网络字节序的端口 转换成 主机字节序的…

理解字节序 大端字节序和小端字节序

以下内容参考了 http://www.ruanyifeng.com/blog/2016/11/byte-order.html https://blog.csdn.net/yishengzhiai005/article/details/39672529 1. 计算机硬件有两种储存数据的方式&#xff1a;大端字节序&#xff08;big endian&#xff09;和小端字节序&#xff08;little …

什么是字节序?

字节序 字节序&#xff0c;顾名思义&#xff0c;就是字节组织的顺序。我们可以将其根据其存储时从低位开始还是从高位开始分为两种&#xff0c;具体如下&#xff1a; 类型简写本质大端BE(big endian)将高序字节存储在起始地址小端LE(little endian)将低序字节存储在起始地址 …

网络字节序和主机字节序详解(附代码)

一、网络字节序和主机字节序 网络字节序和主机字节序是计算机网络中常用的两种数据存储格式。 主机字节序&#xff1a; 指的是在计算机内部存储数据时采用的字节排序方式。对于一个长为4个字节的整数&#xff0c;若采用大端字节序&#xff0c;则该整数在内存中的存储顺序是&a…

字节序

1.字节序 字节序&#xff0c;又称端序或尾序&#xff0c;指的是多字节数据在内存中的存放顺序。例如一个int型变量x占用4个字节&#xff0c;假设它的起始地址&x为0x10&#xff0c;那么x将会被存储在 0x10、0x11、0x12和0x13位置上。 在用C写的客户端和Java写的服务端的通…

字节序详细解读

概念来了&#xff01;&#xff01;&#xff01; 字节序&#xff08;Byte Order&#xff09;是指多字节数据在计算机内存中存储或者网络传输时各字节的存储顺序。 在计算机中是以字节为单位&#xff0c;每个地址对应一个字节&#xff0c;一个字节8bit。在C中&#xff0c;除了8bi…

JitPack的简单使用

JitPack的简单使用 由于工作需要,我要搭建多个项目,但是每个项目的基类,工具包,自定义的view,都是一样的,需要将这些代码复制到好几个项目里,所以萌生了一个想法,将这些基本不会改变的代码,做成一个依赖,一行代码引入项目 打开你的项目Git地址,创建发行版本 打开jitpack官网…

Gitee项目发布到JitPack

Gitee项目发布到JitPack 发布前的准备将Gitee项目发布到jitPack使用自己发布的库 发布前的准备 1.搜先注册一个Gitee账号 2.新建一个本地的android项目&#xff0c;并上传到Gitee。 (1) 根目录下build.gradle配置 dependencies {...classpath "com.android.tools.build:g…

【jitpack】android implementation 远程仓库

目录 前言接入步骤使用说明问题后记结束语 前言 做android的小伙伴都知道&#xff0c;android studio 在使用其他三方项目的时候使用gradle来管理版本,如直接使用如下就能快速把 appcopmt-v7 引入到项目中使用 implementation com.android.support:appcompat-v7:28.0.0 其实…

【JitPack】发布一个你自己的 Android 依赖库

文章目录 背景步骤新建 Android Library 项目配置 Gradle提交项目到 githubPull Request 到主分支创建 tag 并发布 release 版本JitPack 生成项目的依赖库第三方应用集成使用依赖库 JitPack 生成依赖库的 pom.xml 文件地址参考链接 背景 最近突然想开发个 Android Library&…

Android私有库gitee发布到JitPack后,编译通过但依赖不到。

JitPack编译通过后点击查看log只有这个&#xff1a; Subscription is not active right now Requested subscription: gitee.com/huile_1_0. Your subscriptions are listed in https://jitpack.io/w/user Please contact Support or repository admins if you need assistanc…

JitPack让第三方依赖更简单(第一种方法)

前面我们讲了如何将我们开发常用的工具发布到jcenter&#xff0c;然后进行依赖&#xff0c;这样有利于提高开发的效率&#xff0c;但是&#xff0c;又出现了一种新的发布方式&#xff0c;虽然现在使用的人还没有jcenter多&#xff0c;但是个人感觉未来使用的人会超过jcenter&am…

Android自定义library上传到JitPack

一、背景 最近公司不是太忙&#xff0c;闲的无聊&#xff0c;准备整理下属于自己的library库&#xff0c;想把自己平时用到的库保存起来到JitPack上&#xff0c;用的时候直接依赖添加。下面是我们把library发布到JitPack上去的记录过程。 二、项目配置 1.版本不同配置方法有些不…

maven { url “https://jitpack.io“ }

maven { url "https://jitpack.io" } 不能写在项目的build.gradle里面&#xff0c;要写在项目的setting.gradle

AndroidStudio之https://jitpack.io

前言 很多小伙伴自己写了一个库,打算开源出来,但是直接给别人发jar包或者aar包,别人使用都很不方便,而且版本更新也不方便,所以很多小伙伴把开源库放到了远程仓库里(如maven或jcenter),但是麻烦就麻烦在需要打包导出等。 而今天我要推荐一个超级方便的远程仓库:https://jitpa…

Android 发布代码到github 并且部署到 JitPack maven 仓库详细步骤

废话不多说&#xff0c;直接上步骤干货 Step1 在项目根目录的build.gradle 文件中加入 buildscript {repositories {maven { url https://jitpack.io }}dependencies {classpath com.github.dcendents:android-maven-gradle-plugin:2.1} }allprojects {repositories {maven {…

JitPack让第三方依赖更简单(第二种方法)

文章目录 前言步骤使用结语 每日一句正能量 如果青春是醺人欲醉的海风&#xff0c;那么自信就是这和风前行的路标&#xff0c;如果青春是巍峨入云的高耸&#xff0c;那么拼搏就是这山脉层层拔高的动力&#xff1b;如果青春是高歌奋进的谱曲&#xff0c;那么坚强就是这旋律奏响的…