用回溯法解决圆排列问题

article/2025/9/20 20:10:35


教材是用的王晓东的《计算机算法设计与实现》第四版,c++版

一下是问题描述:

算法实现:

/**
*能确定一个正确的想法(即每种情况都能考虑到,然后找一个最简单而准确的方式表达出来)
*
**/ #include<iostream>//此问题没有要求相邻的圆必须相切


#include<math.h>
using namespace std;
class Circle{
 friend float CirclePerm(int,float*);//找到最优排列
 private:
  float Center(int t);//计算横坐标
  void Compute();//计算当前圆排列的长度
  void Backtrack(int t);
  float min,//最优值
  *x,//当前圆排列圆心横坐标
  *r; //当前元的半径
  int n;//当前待排园的个数
 
};
template <class T>
void Swap(T a,T b)
{
 T temp;
 temp = a;
 a = b;
 b = temp;
}
//此问题没有要求相邻的圆必须相切 ——对于计算横坐标,肯定选最大值
float Circle::Center(int t)//t代表当前选的第t个圆
{
 //计算当前所选园的圆心横坐标
 float temp = 0.0;//第一个圆默认为0
 //j表示第t个圆之前的圆,
 //x[j]这个数组第零个元素无用
 for(int j=1;j<t;j++)//为什么每次都从第一个圆开始比 ——找最大值,防止前一个与之相切的圆特别小 (不是,见下)
 {
  float valuex = x[j]+2*sqrt(r[t]*r[j]);//疑问①  考虑特殊情况 (如果特大圆放在第二个位置,圆心距与横坐标并没有错)——核心问题不是这个,这个两个之间也是相切的
  //另一种特殊情况是第二个圆特别小而第三个圆很大,导致一三相切二三不想切,这就是for循环的原因  
  //疑问二  不考虑特殊情况,为什么要加x[j]? —懂了,画图就明白了,x[j]是之前圆的横坐标
  if(valuex>temp)temp = valuex;
 } 
 return temp;
}
//负轴取绝对值最大,正轴取最大 ,n、

void Circle::Compute(void){//计算当前圆排列的长度,我的想法——(1--j)上所有圆的横坐标加上这个的圆心距取最小值(若最后一个圆特别小,这个公式根本不成立);课本上的想法——(负轴取绝对值最大,正轴取最大)
 float low = 0,
    high= 0;
    for(int i = 1;i<=n;i++)//n始终是不变的
    {
     if(x[i]-r[i]<low)low = x[i]-r[i];//为什么要积累low——也和特殊情况有关吗?             //这个算的就是第一个的半径吧,到底为什么要积累 ——不对,算的是负值的部分,若第一个特别小,第二个很大,则取最大值
     if(x[i]+r[i]>high)high = x[i]+r[i];//这个肯定要去最大值,若最后一个圆特别小,与边框根本不相切,算出来的值则不对
    }
    if(high-low<min)min = high-low;
}
void Circle::Backtrack(int t){
 if(t>n)Compute();
 else
 {
  for(int j=t;j<=n;j++)
  {
   Swap(r[t],r[j]);
   float centerx = Center(t);
   if(centerx+r[t]+r[1]<min){//下界约束
   x[t] = centerx;
   Backtrack(t+1);
   }
   Swap(r[t],r[j]);
  }
 }
}
float CirclePerm(int n,float*a)
{
 Circle X;
 X.n= n;
 X.r= a;
 X.min = 1000000;
 float*x = new float[n+1];
 X.x = x;
 X.Backtrack(1);
 delete[] x;
 return X.min;
}
int main()
{
 int n;
 float*a = new float[n+1];
 cin>>n;
 for(int i=1;i<=n;i++)
 {
  cin>>a[i];
 }
 cout<<CirclePerm(n,a)<<endl;
 return 0;                                                                                                                                                                                                            
}



注意:

算法部分来源于课本

此算法中的出来的是最优解

考虑到了相邻圆之间可能不相切的情况


在看算法的过程中提了很多智障问题,都在注释里面,但也都自圆其说了,望大佬们如果发现有错误的,可以不吝赐教。



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

相关文章

回溯法之圆排列问题

问题描述 给定n个大小不等的圆c1,c2,…,cn&#xff0c;先要将这n个圆排进一个矩形框中&#xff0c;且要求各圆与矩形框的底边相切。圆排列问题要求从n个圆的所有排列中找出有最小长度的圆排列。例如&#xff0c;当n3时&#xff0c;且所给的3个圆的半径分别为1、1、2时&#xf…

5-10 圆排列问题(回溯)

5-10 圆排列问题(回溯) 给定n个大小不等的圆c1, c2,…, cn&#xff0c;现要将这n个圆排进一个矩形框中&#xff0c;且要求各圆与矩形框的底边相切。圆排列问题要求从n个圆的所有排列中找出有最小长度的圆排列。 例如&#xff0c;当n3&#xff0c;且所给的3个圆的半径分别为1&a…

【2019华为笔试】召唤师的技能——圆排列,翻转和项链排列

题目描述&#xff1a; dota游戏里面&#xff0c;召唤师可以控制冰雷火三种元素&#xff0c;并通过元素组合产生新的技能。现在我们修改了张新的地图&#xff0c; 地图中他能够控制n种元素&#xff0c; 并且将m个元素围成一个圈组成一 个新技能(这m个元素通过旋转或反转&#x…

圆排列问题

问题 圆排列问题&#xff1a;给定n个圆的半径序列&#xff0c;将它们放到矩形框中&#xff0c;各圆与矩形底边相切&#xff0c;求具有最小排列长度的圆排列。 解析 首先对于这个问题&#xff0c;使用分支限界计算&#xff0c;一定会遍历所有的排列情况&#xff0c;剪枝就是当前…

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

参考资料 https://blog.csdn.net/liufeng_king/article/details/8890603https://blog.csdn.net/qq_32400847/article/details/51474105https://blog.csdn.net/yzmck/article/details/4302554 原理解释的很赞http://www.doc88.com/p-079198350775.html http://www.docin.com/p-…

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

问题描述 给定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…