分享

算法设计与分析 5.10 圆排列问题

 shaobin0604@163.com 2006-10-10

/***********************************************************
 *                  5.10 圆排列问题
 * 1.问题描述
 * 给定 n 个大小不等的圆 c1, c2, c3, ..., cn, 现在要将这 n 个圆排进
 * 一个矩形框中,且要求各圆与矩形框的底边相切。圆排列问题要求从 n 个圆的
 * 所有排列中找出有最小长度的圆排列。
 *
 * 2.算法设计
 * 圆排列问题的解空间是一棵排列树。按照回溯法搜索排列树的算法框架,设开始
 * 时 a = [r1, r2, ..., rn] 是所给的 n 个圆的半径,则相应的排列树由
 * a[1, .., n] 的所有排列构成。
 *
 * 3.复杂度
 * O(n!)
 */
public class Circles {
 static int n;   //待排列的圆的个数
 static float min;  //当前最优值
 static float[] x;  //当前圆排列圆心横坐标
 static float[] r;  //当前圆排列
 
 public static float circlePerm(int nn, float[] rr) {
  n = nn;
  min = Float.MAX_VALUE;
  x = new float[n];
  r = rr;
  trackback(0);
  return min;
 }

 private static void trackback(int t) {
  if (t == n - 1) {
   compute();
  } else {
   for (int j = t; j < n; j++) {
    swap(r, t, j);
    float centerx = center(t);
    if (centerx + r[t] + r[0] < min) { //下界约束
     x[t] = centerx;
     trackback(t + 1);
    }
    swap(r, t, j);
   }
  }
  
 }

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

 private static void compute() {
  // 计算当前圆排列的长度
  float low = 0;
  float high = 0;
  for (int i = 0; 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 < min)
   min = high - low;  
 }
 
 private static void swap(float[] array, int i, int j) {
  float temp = array[i];
  array[i] = array[j];
  array[j] = temp;
 }
}
 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多