[JSOI2004]平衡点

题目:洛谷P1337。

题目大意:
有n个重物,每个重物有一个重量w,并且绑在一条绳子上。这些绳子在桌面上打成一个结。问结在哪里才能使重物平衡。
解题思路:
题意就是要求\(\sum\limits_{i=1}^n d_i\times w_i\)最小(\(d_i\)为重物i到结的距离)。
模拟退火即可。

C++ Code:

#include<bits/stdc++.h>
#define eps 1e-15
#define delta 0.991
struct things{
	int x,y,w;
}p[1005];
struct Answer{
	double x,y,w;
}ans,start,now;
int n,xxx=0,yyy=0;
inline int readint(){
	int d=0,c=getchar(),f=0;
	for(;!isdigit(c);c=getchar())f=c=='-';
	for(;isdigit(c);c=getchar())d=(d<<3)+(d<<1)+(c^'0');
	return f?-d:d;
}
inline double calc(const double xx,const double yy){
	double r=0;
	for(int i=1;i<=n;++i){
		double x=p[i].x-xx,y=p[i].y-yy;
		r+=sqrt(x*x+y*y)*p[i].w;
	}
	return r;
}
int main(){
	n=readint();
	for(int i=1;i<=n;++i){
		xxx+=(p[i].x=readint()),yyy+=(p[i].y=readint());
		p[i].w=readint();
	}
	ans=start=(Answer){1.*xxx/n,1.*yyy/n,calc(1.*xxx/n,1.*yyy/n)};
	srand(time(0));
	for(int T=20;T;--T){
		now=start;
		for(double nT=5333;nT>eps;nT*=delta){
			double nx=now.x+((rand()<<1ll)-RAND_MAX)*nT;
			double ny=now.y+((rand()<<1ll)-RAND_MAX)*nT;
			double res=calc(nx,ny);
			if(res<ans.w)ans=(Answer){nx,ny,res};
			if(res<now.w||exp((res-now.w)/nT)*RAND_MAX<rand())
			now=(Answer){nx,ny,res};
		}
	}
	printf("%.3f %.3f\n",ans.x,ans.y);
	return 0;
}

 

posted @ 2018-06-13 18:02  Mrsrz  阅读(214)  评论(0编辑  收藏  举报