洛谷p1137 模拟退火

题目链接:https://www.luogu.org/problem/P1337

以x为原点,将力分解成横纵方向的力,每次退火时单独对答案的横纵坐标进行判断是否更新答案

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<cmath>
using namespace std;
#define eps 1e-6
#define maxn 1005
int n;
double T,dx=0.98,X,Y,x,y;
struct node{
    double x,y,w;
}p[maxn],a,ans;
void SA()
{
    T=20000;
    X=0;Y=0;
    a.x=p[rand()%n+1].x;
    a.y=p[rand()%n+1].y;
    while(T>eps)
    {
        double c;
        X=Y=0; 
        for(int i=1;i<=n;i++)
        {
            if(a.x==p[i].x)
            {
                if(a.y<p[i].y)Y+=p[i].w;
                else if(a.y>p[i].y)Y-=p[i].w;
            }
            else if(a.y==p[i].y)
            {
                if(a.x<p[i].x)X+=p[i].w;
                else if(a.x>p[i].x)X-=p[i].w;
            }
            else
            {
                c=sqrt((a.x-p[i].x)*(a.x-p[i].x)+(a.y-p[i].y)*(a.y-p[i].y));
                X+=p[i].w*(p[i].x-a.x)/c;Y+=p[i].w*(p[i].y-a.y)/c;
            }
        }
        c=sqrt(X*X+Y*Y);
        if(x>abs(X))ans.x=a.x,x=abs(X);
        if(y>abs(Y))ans.y=a.y,y=abs(Y);
        a.x+=T*X/20000;
        a.y+=T*Y/20000;
        T*=dx;
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    scanf("%lf%lf%lf",&p[i].x,&p[i].y,&p[i].w);
    ans.x=ans.y=0;a.x=a.y=0;
    x=y=9999999;
    dx=0.99;
    SA();
    dx=0.98;
    SA();
    dx=0.988;
    SA();
    printf("%.3lf %.3lf\n",ans.x,ans.y);
    return 0;
}
/*
3
0 0 1
0 2 1
1 1 1
*/

猜你喜欢

转载自www.cnblogs.com/chen99/p/11700559.html