[省选前题目整理][BZOJ 3680]吊打XXX(模拟退火)

来源:互联网 发布:淘宝双11实时交易额 编辑:程序博客网 时间:2024/05/05 17:25

题目链接

http://www.lydsy.com/JudgeOnline/problem.php?id=3680

思路

非常裸的模拟退火。。。
但是参数很难调,随机数写挫了也会错。。。

代码

#include <iostream>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <algorithm>#include <cmath>#define MAXN 10100 //!!!!!#define INF 1e20#define EPS 1e-3using namespace std;int n;double minans=INF; //最小距离之和struct Point{    double x,y,weight;}points[MAXN],start,cg;double dist(Point a,Point b){    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}double calc(Point center) //计算以center为重心到各点加权距离和{    double ans=0;    for(int i=1;i<=n;i++)        ans+=points[i].weight*dist(points[i],center);    if(ans<minans)    {        minans=ans;        cg=center;    }    return ans;}double Rand(){    return (double)(rand()%1000)/1000;}void SA(Point now){    minans=INF;    double T=1000000;    while(T>EPS)    {        Point next;        next.x=now.x+(Rand()*2-1)*T;        next.y=now.y+(Rand()*2-1)*T;        double dE=calc(now)-calc(next);        if(dE>0||exp(dE/T)>Rand()) now=next;        T*=0.993;    }    for(int i=1;i<=1000;i++) //随机1000次小范围移动    {        Point next;        next.x=cg.x+(Rand()*2-1)*T; //!!!        next.y=cg.y+(Rand()*2-1)*T; //!!!!        calc(next);    }}int main(){    srand(23333333);    scanf("%d",&n);    for(int i=1;i<=n;i++)    {        scanf("%lf%lf%lf",&points[i].x,&points[i].y,&points[i].weight);        start.x+=points[i].x;        start.y+=points[i].y;    }    start.x/=n,start.y/=n;    SA(start);    printf("%.3lf %.3lf\n",cg.x,cg.y);    return 0;}
0 0
原创粉丝点击