模拟退火求二维费马点

一.概念引入

        AC过后,突然想起费马点和最小覆盖圆的圆心有关系吗?答案是没关系,如下图:费马点肯定在等腰梯形内,不是在圆心。

        模拟退火算法与初始值无关,算法求得的解与初始解状态S(是算法迭代的起点)无关;模拟退火算法具有渐近收敛性,已在理论上被证明是一种以概率收敛于全局最优解的全局优化算法;模拟退火算法具有并行性。

        三角形费马点:如果三角形ABC中有一个角的角度大于等于120, 那么该角的顶点就是费马点;如果三角形ABC的三个角的角度都小于120, 那么该三角形的费马点P为满足条件angle APB=angle BPC=angle CPA ,所以三角形的费马点也称为三角形的等角中心。

        牛顿迭代:令f(x,y)=Sigma( sqrt((x-xi)^2 + (y-yi)^2) ),本题要求f(x,y)的最小值,此函数是凸的。可验证极小值唯一,且当p0,p1..pn-1不在一条线上时,极小值点唯一,于是只需求得f'x=f'y=0的点即可。用牛顿迭代法解此二元方程组。

        塞瓦定理:设O是△ABC内任意一点,AO、BO、CO分别交对边于D、E、F,则 BD/DC*CE/EA*AF/FB=1。

        三角形内角平分线定理:今天给大二孩子将计算几何求内切圆圆心用到了。

二.算法实现

        以POJ2420为例,直接去AC吧。

        模拟退火(Simulated Annealing),题目:就是求多边形的费马点,输出最小的距离。讨论群里有人说应该说牛顿迭代是……所有大学生应该想到的……枚举是……高中生想到的……顿时无语。


import java.util.Scanner;

public class POJ2420 {

  static Point[] p;
  static int n;

  public static void main(String[] args) {
    double x;
    double y;
    Scanner sc = new Scanner(System.in);
    while(sc.hasNext()) {
      n = sc.nextInt();
      p = new Point[n];
      for(int i=0; i<n; i++) {
        p[i] = new Point();
      }
      for(int i=0; i<n; i++) {
        x = sc.nextDouble();
        y = sc.nextDouble();
        p[i] = new Point(x,y);
      }
      double ans = solve();
      System.out.println((int)ans);
    }
  }

  private static double solve() {

    Point pre = new Point();
    Point cur = new Point();
    /*
     * 终于找到错了,发现"cur = pre"的话,cur和pre完全一样,
     * 调试里id都是34,内存一样,
     * 我把其他的赋值全部搞成属性赋值就AC了
     * 坑了一天
     */

    double dis = getAllDistance(cur);
    double step = 10000;
    double r = 0.5;
    double[][] d = {{0,1},{0,-1},{-1,0},{1,0}};
    Point node = new Point();
    while(Double.compare(step, 0.2)>0) {
      boolean ok = true;
      while(ok) {
        ok = false;
        /*
         * 下面的赋值是必须的
         * 因为如果下面的for循环没有更新node,
         * 那么for循环后的赋值就没法进行
         */
        node.x = cur.x;
        node.y = cur.y;
        for(int i=0; i<4; i++) {
          //四次循环中cur不能 变
          pre.x = d[i][0]*step + cur.x;
          pre.y = d[i][1]*step + cur.y;
          //由于坐标大于0,所以小于0的坐标定然不是最小值
          if(pre.x<0||pre.y<0) {
            continue;
          }
          double temp = getAllDistance(pre);
//          System.out.println("step:"+step +"  " +
//          "dis:"+dis +"   "+"temp:"+temp+
//          " "+cur.x+"  "+cur.y+"---"+pre.x+"  "+pre.y);
          if(dis>temp) {
            dis = temp;
            node.x = pre.x;
            node.y = pre.y;
            ok = true;
          }
        }
        cur.x = node.x;
        cur.y = node.y;
      }
      step *= r;
    }
    return Math.floor(dis+0.5);
    //return dis;
  }

  private static double getAllDistance(Point cur) {
    double sum = 0;
    for(int i=0; i<n; i++) {
      sum += getDistance(cur,p[i]);
    }
    return sum;
  }

  private static double getDistance(Point a, Point b) {
    return Math.hypot(a.x-b.x, a.y-b.y);
  }

}

class Point {
  double x;
  double y;
  public Point() {
    this.x = 0;
    this.y = 0;
  }
  public Point(double x, double y) {
    super();
    this.x = x;
    this.y = y;
  }
}
时间: 2024-10-07 20:18:24

模拟退火求二维费马点的相关文章

C# 求二维数组内元素 ,求频数最高的值域范围

问题描述 有一二维数据,数组内元素为double类型,每一数组元素不相同,求二维数组内元素,在某一值域范围内出现频数最高的值域范围. 解决方案 解决方案二:没看懂这种题目和二维数组有啥关系先都弄出来变成一维数组不行?还有,值域范围总要有个范围吧,比如在7.5和8.5之间频率高,或者7.0或9.0之间频率高否则直接说负无穷到正无穷之间频率最高,这就是真理,根本不需要计算了解决方案三:double[,]a={{1,5,3.6},{2.2,4.1}};求得{2.2,3.6}是这个意思吧?解决方案四:在

c语言-C语言使用随机分布函数rand()%100;但是二维数组a[0][0]的值大于100,其他正常

问题描述 C语言使用随机分布函数rand()%100;但是二维数组a[0][0]的值大于100,其他正常 #include #include #define M 5 #define N 4 void china(int a[][N],int b[M]);/*给二维数组随机分配数值,并求二维数组每行数值之和*/ void orange(int a[][N],int b[M]);/*将付好值得数组和求和打印出来*/ void main() {int a[M][N],b[N]; china(a,b);

c语言-二维数组大小问题......

问题描述 二维数组大小问题...... int a[100][100] = { 0 }, b[100] = {0}, n, m, j, i, min; printf("输入行和列: "); scanf_s("%d%d", &n, &m); for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) scanf_s("%d", &a[i][j]); for (i = 1;

一维数组,二维数组,三维数组,数组与指针,结构体数组,通过改变指针类型改变访问数组的方式

 打印数组中的每个元素,打印每个元素的地址: #include <stdio.h> #include <stdlib.h>   void main(void) {     int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };     for (int *p = a; p < a + 10;p++)  //指针类型决定4个字节     {         printf("\n%p,%d", p, *p);    

关键操作步骤-利用软件Rsoft,绘出二维光子晶体的透射谱

问题描述 利用软件Rsoft,绘出二维光子晶体的透射谱 目的:求二维光子晶体"透射率-自由空间波长"(透射谱)图. 要求手段:利用Rsoft软件仿真 同类手段:有人使用Matlab绘出过透射谱,也有人使用OptiFDTD 具体要求:请各位说明应该用Rsoft的哪一项功能来绘制透射谱,并说明关键的操作步骤,如果能够附上相应的图片,将更为感谢!

JS中取二维数组中最大值的方法汇总_javascript技巧

在JavaScript中可以通过内置的 Math.max() 的最大值,但是要从多重数组中取出最大值,还是有一定的难度. 问题描述 假设你有一个数组,而且这个数组中包含了数字的子数组,而我们要做的是从数组中的每个子数组中返回其最大的那个最大数. 基本解决方案 function largestOfFour(arr) { var results = []; // 创建一个results变量来存储 // 创建一个外层循环,遍历外层数组 for (var n = 0; n < arr.length; n

二维码 生成 代码

问题描述 跪求二维码生成代码 解决方案 解决方案二:不知,帮你顶下.....求高手

POJ 2420 模拟退火求费马点

题意求一个多边形的费马点,即到所有顶点距离和最小的那一点. 以前觉得模拟退火好高端的样子,实际就是把点往四个方向移动固定步长,知道不能移动后缩小步长继续移动,也就是随机求一个接近最优并且满足精度的解. #include <iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; typedef doub

acm-一道二维数组的ACM题,刚开始接触二维数组,求解答

问题描述 一道二维数组的ACM题,刚开始接触二维数组,求解答 这是题目 Description potato老师虽然很喜欢教书,但是迫于生活压力,不得不想办法在业余时间挣点外快以养家糊口. "做什么比较挣钱呢?筛沙子没力气,看大门又不够帅..."potato老师很是无奈. "张艺谋比你还难看,现在多有钱呀,听说还要导演奥运开幕式呢!你为什么不去娱乐圈发展呢?"lwg在一旁出主意. 嗯,也是,为了生存,就委屈点到娱乐圈混混吧,马上就拍一部激光电影<回来我的爱&g