[JSOI2004]平衡点 / 吊打XXX
考虑模拟退火。
题目要我们找到一个点,使得整个系统平衡。
这个要求等价于让我们找到一个点,使得系统总能量最小。
我们退火出一个点,然后计算其能量即可。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<queue> 6 #include<cstdlib> 7 #include<cmath> 8 #define N 10005 9 using namespace std; 10 int read() 11 { 12 int x=0,f=1;char ch=getchar(); 13 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 14 while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();} 15 return x*f; 16 } 17 struct node 18 { 19 int x,y,w; 20 }a[N]; 21 int n; 22 double t,ansx,ansy,sx,sy,ans=1e18; 23 const double delta=0.993; 24 double calc(double x,double y) 25 { 26 double res=0; 27 for(int i=1;i<=n;i++) 28 { 29 double dtx=x-a[i].x,dty=y-a[i].y; 30 res+=sqrt((dtx*dtx)+(dty*dty))*a[i].w; 31 } 32 return res; 33 } 34 void SA() 35 { 36 double x=ansx,y=ansy; 37 t=2137; 38 while(t>1e-14) 39 { 40 double X=x+((rand()<<1)-RAND_MAX)*t; 41 double Y=y+((rand()<<1)-RAND_MAX)*t; 42 double now=calc(X,Y); 43 double D=now-ans; 44 if(D<0) 45 { 46 x=X;y=Y; 47 ansx=x;ansy=y;ans=now; 48 } 49 else if(exp(-D/t)*RAND_MAX>rand())x=X,y=Y; 50 t*=delta; 51 } 52 } 53 void solve() 54 { 55 ansx=(double)sx/n;ansy=(double)sy/n; 56 SA(); 57 SA(); 58 SA(); 59 SA();SA(); 60 } 61 int main() 62 { 63 srand(44042137); 64 n=read(); 65 for(int i=1;i<=n;i++) 66 { 67 a[i].x=read();a[i].y=read();a[i].w=read(); 68 sx+=a[i].x;sy+=a[i].y; 69 } 70 solve(); 71 printf("%.3lf %.3lf\n",ansx,ansy); 72 return 0; 73 }