【模拟退火】POJ 2420/ZOJ 1901 费马点

来源:互联网 发布:猜数字游戏c语言 编辑:程序博客网 时间:2024/05/15 23:19

n 边形的费马点, 即某一点到n 边形的n 个顶点距离和最小的点。

模拟退火精度会受损。

模拟退火,就是一种贪心算法,但一定要注意得满足一些类似三角不等式的条件才能使用,否则不就不是损精度的问题了,而是根本上就是错误的。

以求费马点为例:

在平面上我先随便选出一点出发,向上下左右4个方向(这里只是以4方向为例,你也可以设8方向等,对于3维的可以设6方向)每个方向都尝试性的迈一步,这一步的大小为step,在所到的4个新地点选一个到所有点距离和最小的,然后你就走到那个点作为下一步的出发点,直到某一时刻四个方向都不如你当前所占的地点优,这是就将step/=2(除2也是灵活的,你也可以除1.5)之后再重复找四个方向。

不能更新的意义就是在当前step的精度下无法再移动,所以要再次缩小精度。这就像在google地图上找scnu公寓一样,先找到中国,再缩小精度(step/=2),再找到gz,在缩小精度,再找到scnu,再缩小精度,再找到xisan。----参考某blog

算法:

先拿一个点(该算法用n 个顶点的x, y 坐标和的均值所在的点)去计算距离和最小值, 然后拿它的四个方向上的点去测试比较哪个点更优, 不断迭代, 最终得到在精度允许下的费马点. 

#include <vector>#include <list>#include <map>#include <set>#include <queue>#include <string.h>#include <deque>#include <stack>#include <algorithm>#include <iostream>#include <iomanip>#include <cstdio>#include <cmath>#include <cstdlib>#include <limits.h>#include <time.h>using namespace std;int lowbit(int t){return t&(-t);}int countbit(int t){return (t==0)?0:(1+countbit(t&(t-1)));}int gcd(int a,int b){return (b==0)?a:gcd(b,a%b);}#define LL long long#define PI acos(-1.0)#define N  110#define MAX INT_MAX#define MIN INT_MIN#define eps 1e-8#define FRE freopen("a.txt","r",stdin)struct node{    double x,y;}p[N];int n;double d[4][2]={{0,1},{0,-1},{1,0},{-1,0}};double dis(node a,node b){    return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));}double dis_all(node a){    int i;    double sum=0;    for(i=0;i<n;i++){        sum+=dis(a,p[i]);    }    return sum;}int main(){    while(scanf("%d",&n)!=EOF){        int i,j,k;        for(i=0;i<n;i++)scanf("%lf %lf",&p[i].x,&p[i].y);        node p0=p[0];        double minm=INT_MAX;        double step;        for(step=1000.0;step>eps;step/=2.0){            int flag=1;            while(flag){                //当再也找不到比当前小的就中止循环,把step缩小再找                flag=0;                for(i=0;i<4;i++){                    node tmp;                    tmp.x=p0.x+d[i][0]*step;                    tmp.y=p0.y+d[i][1]*step;                    double t=dis_all(tmp);                    if(t<minm){                        minm=t;                        p0=tmp;                        flag=1;                    }                }            }        }        printf("%.0f\n",minm);    }    return 0;}


原创粉丝点击