5-34 排列树问题
问题描述
试设计一个用回溯法搜索排列空间树的函数。该函数的参数包括结点可行性判定函数和上界函数等必要的函数,并将此函数用于解圆排列问题。
圆排列问题描述如下:给定 n 个大小不等的圆
,现要将这 n 个圆排进一个矩形框中,且要求各圆与矩形框的底边相切。圆排列问题要求从 n 个圆的所有排列中找出有最小长度的圆排列。
例如,当 n=3,且所给的 3 个圆的半径分别为 1,1,2 时,这 3 个圆的最小长度的圆排 列如图所示,其最小长度为
。
对于给定的 n 个圆,编程计算最小长度排列。
数据输入:
第 1 行是 1 个正整数 n,表示有 n 个圆。第 2 行有 n 个正数,分别表示 n 个圆的半径。
Java
package Chapter5HuiSuFa;
import java.util.Scanner;
public class PaiLieShu {
private static int MAX = 100000;
private static int n;
private static float min,centerx;
private static float[] x,xr;
public static void main(String[] args){
Scanner input = new Scanner(System.in);
while (true){
min = MAX;
n = input.nextInt();
x = new float[n+1];
xr = new float[n+1];
for(int i=1; i<=n; i++)
x[i] = input.nextFloat();
backtrack(1);
output();
}
}
private static void backtrack(int t){
if(t > n) record();
else
for(int i=t; i<=n; i++){
swap(x,t,i);
if(constraint(t) && bound(t)){
change(t);
backtrack(t+1);
restore(t);
}
swap(x,t,i);
}
}
private static void swap(float[] x, int m, int n){
float tmp = x[m];
x[m] = x[n];
x[n] = tmp;
}
private static void record(){
float low=0,high=0;
for(int i=1; i<=n; i++){
if(xr[i]-x[i] < low) low=xr[i]-x[i];
if(xr[i]+x[i] > high) high=xr[i]+x[i];
}
if(high-low < min) min=high-low;
}
private static boolean constraint(int t){
return true;
}
private static boolean bound(int t){
centerx = center(t);
if(centerx+x[t]+x[1] < min) return true;
else return false;
}
private static void change(int t){
xr[t] = centerx;
}
private static void restore(int t){
}
private static float center(int t){
float temp = 0;
for(int j=1; j<t; j++){
float valuex = (float) (xr[j]+2.0*Math.sqrt(x[t]*x[j]));
if(valuex > temp) temp=valuex;
}
return temp;
}
private static void output(){
System.out.println(String.format("%.5f",min));
}
}
Input & Output
3
1 1 2
7.65685
9
17 49 77 84 86 64 75 88 65
1159.66772
Reference
王晓东《计算机算法设计与分析》(第3版)P188