圆排列问题

1.问题

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

2.解析

给定n个圆c1,c2,…,cn,将这n个圆排进一个矩形框中,且要求各圆与矩形框的底边相切。圆排列问题要求从n个圆的所有排列中找出有最小长度的圆排列。
在这里插入图片描述
先输入的n个圆半径,接着计算出最小长度和当前选择的圆中心的横坐标,最后算排列。圆排列问题的解空间是一棵排列树。 设置函数来找到的最小的圆排列长度。开始时,数组a储存的n个圆的半径,计算返回最优解的圆排列,还需计算当前圆排列中的圆的横坐标,并计算当前圆排列的长度,接着找出当前最小圆排列长度。

3.设计

要把计算圆心坐标的公式放在一个for循环里面 , 排在任意位置的圆与其前或后的任意一个圆都有可能相切的 。在这之中要清楚目标圆有可能与排列中的任意一个圆相切,假设x[3]的坐标只能从前往后比较,先得到x[1]+a的值(即x[3]的可能坐标,再得到x[2]+b的值,与上一次的可能值相比较,若距离更大则更新,否则不边。

// 算计以后所择选圆的圆心横坐标
double cricle :: circle_center (int t)
{
double temp=0;
for (int j=1;j<t;j++)
{
// 算计以后所择选圆的圆心横坐标
double valuex=x[j]+2.0sqrt(r[t]r[j]);
if (valuex>temp)
{
temp=valuex;
}
}
return temp;
}
由x^2 = sqrt((r1+r2)2-(r1-r2)2)推导出x = 2
sqrt(r1
r2),
计算圆在当前圆排列中的横坐标:
double cricle :: circle_center (int t)
{
double temp=0;
for (int j=1;j<t;j++)
double valuex=x[j]+2.0*sqrt(r[t]*r[j]);//计算圆在当前圆排列中的横坐标:

    if (valuex>temp)
	{
		temp=valuex;
	}
 return temp;

}
class cricle
{
friend double Cricle_p(int,double *);
private:
double circle_center (int t);
//后边圆的圆心心的横坐标
void Compute();
//以后的圆排列的度长
void back(int t);

	double min,	 
		  *x,   
		  //圆心横坐标
		  *r;   
		  //圆排列
    int n;      
	//圆的个数

};
// 算计圆排列的度长
void cricle ::Compute(void) // 算计圆排列的度长

{
double L ,H ;
for (int i = 1;i <= n; i++)
{
if (x[i]-r[i]<L)
{
L=x[i]-r[i];
}

    if (x[i]+r[i]>H)
	{
		H=x[i]+r[i];
	}
}
if (H-L<min)
{
	min=H-L;
}

}

4.分析

最坏情况下需要计算O(n!)次圆排列长度,而起每次计算需要O(n)计算时间,所以平均时间复杂性为O((n+1)!)
时间复杂性为O((n+1)!)

5. 源码

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;

const int N = 100;

double Cricle_p(int n,double *a);
int main()
{
int n;
printf(“请输入圆的个数:” );
scanf("%d",&n);
double *a = new double[n+1];
printf(“请输入每个圆的半径:” );

for(int i=1; i<=n; i++)
{
	scanf("%lf",&a[i])  ;
}

printf("请具有最小排列长度::" );
printf("%.3f",Cricle_p(3,a) );
 
 
return 0;

}
template
inline void swap1(T &a, T &b)
{
T t=a;
a=b;
b=t;
}

class cricle
{
friend double Cricle_p(int,double *);
private:
double circle_center (int t);
//后边圆的圆心心的横坐标
void Compute();
//以后的圆排列的度长
void back(int t);

	double min,	 
		  *x,   
		  //圆心横坐标
		  *r;   
		  //圆排列
    int n;      
	//圆的个数

};
double Cricle_p(int n,double *a)
{ double *cir_x = new double[n+1];
cricle coor;
coor.n = n;
coor.r = a;
coor.min = 1000;
coor.x = cir_x;
coor.back(1);
delete []cir_x;
return coor.min;
}

// 算计以后所择选圆的圆心横坐标
double cricle :: circle_center (int t)
{
double temp=0;
for (int j=1;j<t;j++)
{

    double valuex=x[j]+2.0*sqrt(r[t]*r[j]);
    if (valuex>temp)
	{
		temp=valuex;
	}
}
return temp;

}

// 算计圆排列的度长
void cricle ::Compute(void)
{
double L ,H ;
for (int i = 1;i <= n; i++)
{
if (x[i]-r[i]<L)
{
L=x[i]-r[i];
}

    if (x[i]+r[i]>H)
	{
		H=x[i]+r[i];
	}
}
if (H-L<min)
{
	min=H-L;
}

}

void cricle ::back(int t)
{
if (t>n)
{
Compute();
}
else
{
for (int j = t; j <= n; j++)
{
swap1(r[t], r[j]);
double centerx= circle_center (t);
if (centerx+r[t]+r[1]<min)
{
x[t]=centerx;
back(t+1);
}
swap1(r[t], r[j]);
}
}
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值