题解:[JSOI2004]平衡点 / 吊打XXX

这个题目算是一个模拟退火的板子题
  物重一定,绳子越短,重物越低,势能越小,势能又与物重成正比
  使得$\sum_{i=1}^nd[i]*w[i]$也就是总的重力势能最小,可以使得系统平衡

交了两面半。。。我怕是非洲大酋长

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include<ctime>
using namespace std;

#define il inline
#define re register
#define ll long long
#define gc getchar()
inline int read()
{
 	re int x(0),f(1);re char c(gc);
    while(c>'9'||c<'0')f=c=='-'?-1:1,c=gc;
    while(c>='0'&&c<='9')x=x*10+c-48,c=gc;
    return f*x;
}

const int N=10100;
const double D=0.98,eps=1e-15;
double  n;
double x[N],y[N],w[N];

il double f(double p,double q)
{
	double d=0;
	for(int i=1;i<=n;++i)
		d+=w[i]*sqrt((p-x[i])*(p-x[i])+(q-y[i])*(q-y[i]));
	return d;
}

double dx,dy,T,nx,ny,ns,ax,ay,as,ds;

il void sa()
{
	for(int i=1;i<=n;++i)
		dx+=x[i],dy+=y[i];
	dx/=n,dy/=n,ds=f(dx,dy);
	T=101000;
	while(T>eps)
	{
		nx=dx+((rand()*2)-RAND_MAX)*T;
		ny=dy+((rand()*2)-RAND_MAX)*T;
		ns=f(nx,ny);
		if(ns<ds)
			dx=nx,dy=ny,ds=ns;
		else if(rand()<exp((ds-ns)/T)*RAND_MAX)
			dx=nx,dy=ny,ds=ns;
        T*=D;
		if(ds<as) as=ds,ax=dx,ay=dy;
	}
}

int main()
{
	srand(time(0));
	n=read();
	for(int i=1;i<=n;++i)
		scanf("%lf%lf%lf",x+i,y+i,w+i);
	ax=x[1],ay=y[1];as=f(x[1],y[1]);
	sa(),sa(),sa(),sa();
    printf("%.3lf %.3lf",ax,ay);	
	return 0;
}

  

猜你喜欢

转载自www.cnblogs.com/zijinjun/p/10786758.html
今日推荐