1. 程式人生 > >[JSOI2004]平衡點

[JSOI2004]平衡點

題意 code span body alc ++i long const lin

題面在這裏

題意

...見鏈接吧

sol

在此發一篇模擬退火的題解
不得不說luogu的數據真是太良心

一句話解釋模擬退火:在一個慢慢縮小的範圍內隨機狀態尋找最優解,當轉移狀態更優時直接接受,當當前狀態更優時以一定概率\((exp(dlt/T))\)接受
具體實現請參照代碼

#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<iomanip>
#include<cstring>
#include<vector>
#include<cstdio> #include<string> #include<bitset> #include<cmath> #include<queue> #include<stack> #include<map> #include<set> #define sqr(x) ((x)*(x)) #define pb push_back #define RG register #define il inline using namespace std; const int mod=1e9+7
; const int N=1010; typedef unsigned long long ull; typedef vector<int>VI; typedef long long ll; typedef double dd; il ll read(){ RG ll data=0,w=1;RG char ch=getchar(); while(ch!=‘-‘&&(ch<‘0‘||ch>‘9‘))ch=getchar(); if(ch==‘-‘)w=-1,ch=getchar(); while(ch<=‘9‘&&ch>=‘0‘
)data=data*10+ch-48,ch=getchar(); return data*w; } int n;dd mn; struct point{dd x,y,w;}p[N],ans,now; il dd make(){return rand()%100000/100000.00;} il dd dis(point a,point b){return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));} il dd calc(point x){ RG dd ret=0; for(RG int i=1;i<=n;i++) ret+=p[i].w*dis(x,p[i]); return ret; } il void SA(point x){ RG dd T=1e6; while(T>1e-3){//退火過程 now.x=ans.x+T*(2*make()-1); now.y=ans.y+T*(2*make()-1); double dlt=calc(ans)-calc(now); if(dlt>0||exp(dlt/T)>make())ans=now; T*=0.996; } for(int i=1;i<=50000;++i)//最後在一定範圍內搜尋到局部最優解 { now.x=ans.x+T*(2*make()-1); now.y=ans.y+T*(2*make()-1); if(calc(ans)-calc(now)>0)ans=now; } } int main() { srand(time(NULL)+rand()); n=read(); for(RG int i=1;i<=n;i++) scanf("%lf%lf%lf",&p[i].x,&p[i].y,&p[i].w); ans=(point){make(),make(),0};mn=ans.w=calc(ans); SA(ans); printf("%.3lf %.3lf\n",ans.x,ans.y); return 0; }

考試騙分,模擬退火,你值得擁有!

[JSOI2004]平衡點