算法设计与分析: 6-8 圆排列问题

6-8 圆排列问题

问题描述

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

《算法设计与分析: 6-8 圆排列问题》

对于给定的 n 个圆,设计一个优先队列式分支限界法,计算 n 个圆的最佳排列方案,使 其长度达到最小。

数据输入:
第一行有 1 个正整数 n (1≤n≤20)。接下来的 1 行有 n 个数,表示 n 个圆的半径。

Java

package Chapter6FenZhiXianJieFa;

import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Scanner;

public class YuanPaiLie {

    private static class Circle implements Comparable{
        float len;//当前圆排列的长度
        float[] x;//当前圆排列圆心横坐标
        float[] r;//当前圆排列
        int s;    //待排列圆的个数

        public int compareTo(Object o){
            Circle circle = (Circle) o;
            int result = Float.compare(len, circle.len);

            return result;
        }

        //计算当前所选圆的圆心横坐标
        private float center(int t){
            float temp = 0;
            for(int j=1; j<t; j++){
                float valuex = x[j]+(float)(2.0*Math.sqrt(r[t]*r[j]));
                if(valuex > temp) temp=valuex;
            }

            return temp;
        }

        //计算当前圆排列的长度
        private void compute(int ii){
            float low=0,high=0;
            for(int i=1; i<=ii; i++){
                if(x[i]-r[i] < low) low=x[i]-r[i];
                if(x[i]+r[i] > high) high=x[i]+r[i];
            }

            len = high-low;
        }
    }

    private static int MAX = 100000;
    private static int n;
    private static float[] p,B;

    public static void main(String[] args){
        Scanner input = new Scanner(System.in);

        while (true){
            n = input.nextInt();

            p = new float[n+1];
            B = new float[n+1];

            for(int i=1; i<=n; i++)
                B[i] = input.nextFloat();

            System.out.println(String.format("%.5f",circlePerm(B, n)));
            for(int i=1; i<=n; i++)
                System.out.print((int)p[i]+" ");
        }
    }

    private static float circlePerm(float[] a, int n){
        Queue<Circle> H = new PriorityQueue<>();
        Circle E = new Circle();
        E.x = new float[n+1];
        E.r = new float[n+1];
        E.r=a; E.s=0; E.len=MAX;
        float minLen = MAX;
        do{
            if(E.s == n-1){
                E.x[n] = E.center(n);
                E.compute(n);
                if(E.len < minLen){
                    p=E.r; minLen=E.len;
                }
            }else {
                for(int i=E.s+1; i<=n; i++){
                    Circle N = new Circle();
                    N.x = new float[n+1];
                    N.r = new float[n+1];
                    N.s=E.s+1; N.len=E.len;
                    for(int j=1; j<=n; j++){N.x[j]=E.x[j]; N.r[j]=E.r[j];}
                    N.r[N.s]=E.r[i]; N.r[i]=E.r[N.s];
                    N.x[N.s]=N.center(N.s);
                    N.compute(N.s);
                    if(N.len < minLen) H.add(N);
                }
            }
            if(H.isEmpty()) return minLen;
            else E = H.poll();
        }while (E.len < minLen);

        return minLen;
    }

}

Input & Output

3
1 1 2
7.65685
1 2 1 


9
17 49 77 84 86 64 75 88 65 
1159.66772
77 65 86 49 88 64 17 84 75 


7
25 1 5 74 47 77 8 
415.08914
47 1 8 77 5 25 74 

Reference

王晓东《计算机算法设计与分析》

    原文作者:分支限界法
    原文地址: https://blog.csdn.net/IOIO_/article/details/81176578
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞