hoj 1061 排列树问题

本文提出了一种使用回溯法解决圆排列问题的方法。该问题要求在所有可能的排列中找到使得多个圆放置在一个矩形框底边时总长度最小的排列方式。通过递归地尝试不同排列并计算每个排列的总长度来实现这一目标。

Problem C:排列树问题

Time Limit:5000MS  Memory Limit:65536K
Total Submit:55 Accepted:3

Description

试设计一个用回溯法搜索排列空间树的函数。该函数的参数包括结点可行性判定函数和上界函数等必要的函数,并将此函数用于解圆排列问题。
圆排列问题描述如下:给定n 个大小不等的圆c1 , c2 ,..., cn ,现要将这n 个圆排进一个矩形框中,且要求各圆与矩形框的底边相切。圆排列问题要求从n 个圆的所有排列中找出有最小长度的圆排列。例如,当n=3,且所给的3 个圆的半径分别为1,1,2 时,这3 个圆的最小长度的圆排列是1,2,1,其最小长度为2 + 4*sqr(2)。
编程任务:
对于给定的n(n≤≡10)个圆,编程计算最小长度排列。

Input

输入由多组测试数据组成。
每组测试数据输入的第一行是1 个正整数n,表示有n个圆。第2行有n个正数,分别表示n个圆的半径。

Output

对应每组输入,输出的每行是计算出的最小长度,保留3 位小数。

Sample Input

3
1 1 2

 

Sample Output

7.657

 

[Submit]   [Go Back]   [Status]   [Clarify]

 

#include  < iostream >
#include 
< cmath >
#define  MAX 13
using   namespace  std;
int  nn;
class  Circle
{
private :
    
double  mmin,   // ??????????
        x[MAX],    // ????????????????????
        r[MAX];   // ??????????
     int  n;    // ??????????????
public :
    Circle()
    {
        mmin
= 100000000 ;
    }
    
void  Set();
    
void  Swap( int  i, int  j);
    
double  Center( int  t);
    
void  Computer();
    
void  Backtrack( int  t);
    
double  GetMmin();
};
void  Circle::Set()
{
    
int  i;
    n
= nn;
    
for (i = 1 ;i <= n;i ++ )
    {
        scanf(
" %lf " , & r[i]);
        x[i]
= 0 ;
    }
}
void  Circle::Swap( int  i, int  j)
{
    
double  temp;
    temp
= r[i];
    r[i]
= r[j];
    r[j]
= temp;
}
double  Circle::Center( int  t)   // ????????????????????????????
{
    
int  j;
    
double  temp = 0 ,valuex;
    
for (j = 1 ;j < t;j ++ )
    {
        valuex
= x[j] + 2.0 * sqrt(r[t] * r[j]);
        
if (valuex > temp)
            temp
= valuex;
    }
    
return  temp;
}
void  Circle::Computer()    // ??????????????????
{
    
double  low = 0 ,high = 0 ;
    
int  i;
    
for (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 < mmin)
        mmin
= high - low;
}
void  Circle::Backtrack( int  t)
{
    
int  j;
    
double  centerx;
    
if (t > n)
        Computer();
    
else
    {
        
for (j = t;j <= n;j ++ )
        {
            Swap(t,j);
            centerx
= Center(t);
            
if (centerx + r[t] + r[ 1 ] < mmin)
            {
                x[t]
= centerx;
                Backtrack(t
+ 1 );
            }
            Swap(t,j);
        }
    }
}
double  Circle::GetMmin()
{
    
return  mmin;
}
/* double Circle::CirclePerm(int n,double *a)
{
    Circle X;
    X.n=n;
    X.r=a;
    X.mmin=1000000000;
    double *x=new double[n+1];
    X.x=x;
    X.Backtrack(1);
    delete [] x;
    return X.mmin;
}
*/
int  main()
{
    
while (cin >> nn)
    {
        Circle X;
        X.Set();
        X.Backtrack(
1 );
        printf(
" %0.3lf\n " ,X.GetMmin());
    }
    
return   0 ;
}


 

转载于:https://www.cnblogs.com/forever4444/archive/2009/06/04/1495970.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值