随机化算法


模拟退火

P1337 [JSOI2004]平衡点 / 吊打XXX

题目描述

如图:有n个重物,每个重物系在一条足够长的绳子上。每条绳子自上而下穿过桌面上的洞,然后系在一起。图中X处就是公共的绳结。假设绳子是完全弹性的(不会造成能量损失),桌子足够高(因而重物不会垂到地上),且忽略所有的摩擦。

问绳结X最终平衡于何处。

注意:桌面上的洞都比绳结X小得多,所以即使某个重物特别重,绳结X也不可能穿过桌面上的洞掉下来,最多是卡在某个洞口处。

输入格式

文件的第一行为一个正整数n(1≤n≤1000),表示重物和洞的数目。接下来的n行,每行是3个整数:Xi.Yi.Wi,分别表示第i个洞的坐标以及第 i个重物的重量。(-10000≤x,y≤10000, 0<w≤1000 )

输出格式

你的程序必须输出两个浮点数(保留小数点后三位),分别表示处于最终平衡状态时绳结X的横坐标和纵坐标。两个数以一个空格隔开。

输入输出样例

输入 #1
3
0 0 1
0 2 1
1 1 1
输出 #1
0.577 1.000

说明/提示

[JSOI]

      

 1 // luogu-judger-enable-o2
 2 // luogu-judger-enable-o2
 3 
 4 #include<bits/stdc++.h>  
 5 #define re register int 
 6 #define down 0.9986
 7 using namespace std;
 8 int n;
 9 const int maxn=1000+5;
10 double ansx,ansy,answ;
11 int x[maxn],y[maxn],w[maxn];
12 double ener(double  nx,double ny)
13 {
14     double sum=0,dx,dy;
15     for(re i=1;i<=n;i++)
16     {
17         dx=nx-x[i];
18         dy=ny-y[i];
19         sum+=(sqrt(dx*dx+dy*dy))*w[i];
20     }
21     return sum;
22 }
23 void SA()
24 {
25     double t=3000;
26     while(t>1e-15)
27     {
28         double ax=ansx+(rand()*2-RAND_MAX)*t;
29         double ay=ansy+(rand()*2-RAND_MAX)*t;
30         double ans=ener(ax,ay);
31         double del=ans-answ;
32         if(del<0)
33         {
34             answ=ans;
35             ansx=ax;
36             ansy=ay;
37          } 
38          else if(exp(-del/t)*RAND_MAX>rand())
39          {
40             ansx=ax;
41             ansy=ay;
42          } 
43          t*=down;
44     }
45 
46 }
47 void work()
48 {
49     SA();
50     SA();
51     SA();
52     SA();
53     SA();
54 }
55 
56 int main()
57 {
58     cin>>n;
59     for(re i=1;i<=n;i++) 
60     {
61     cin>>x[i]>>y[i]>>w[i];
62     ansx+=x[i];
63     ansy+=y[i];}
64     ansx/=n;
65     ansy/=n;
66     answ=ener(ansx,ansy);
67     work();
68     printf("%.3lf %.3lf
",ansx,ansy);
69     return 0;
70 }
View Code
原文地址:https://www.cnblogs.com/3200Pheathon/p/11598729.html