luogu1337JSOI2004平衡点 / 吊打XXX(模拟退火)

Posted 小哈里

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luogu1337JSOI2004平衡点 / 吊打XXX(模拟退火)相关的知识,希望对你有一定的参考价值。

problem

solution

题意:

  • 给出n个重物的坐标和重量,他们通过一根绳子穿过正上方的洞连在桌面上的某个绳结处,求该绳结的坐标位置。

思路:

  • 根据物理知识:当系统处于平衡状态时,系统的总能量最小。此时系统的总能量是等于各个物体的重力势能,在质量一定时,即要求物体离地最近,离桌子最远。那么,也就是绳子在桌子上的距离尽量的小。
  • 模拟退火,每次随机一个桌子上的点,判断n个洞口到他的总距离和是大了还是小了,找最小的即可。其实就是之前写过的“星星还是树”,就是空间n个点,找距离和最近的点即可。
#include<bits/stdc++.h>
using namespace std;

int n;
struct node{int x, y, w;}a[2020];
struct node2{double x, y, w;}ans;
double calc(double x, double y){//计算系统总能量
	double res = 0;
	for(int i = 1; i <= n; i++){
		double dx=x-a[i].x, dy=y-a[i].y;
		res += sqrt(dx*dx+dy*dy)*a[i].w;
	}
	return res;
}
void sa(){
	for(double t=3000; t >= 1e-15; t*=0.996){
		node2 tmp;
		tmp.x = ans.x+(rand()*2-RAND_MAX)*t;
		tmp.y = ans.y+(rand()*2-RAND_MAX)*t;
		tmp.w = calc(tmp.x, tmp.y);
		double dt =tmp.w-ans.w;
		if(dt<0)ans = tmp;
		else if(exp(-dt/t)>(double)rand()/RAND_MAX)ans=tmp;
	}
}

int main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	cin>>n;
	for(int i = 1; i <= n; i++){
		cin>>a[i].x>>a[i].y>>a[i].w;
		ans.x+=a[i].x, ans.y+=a[i].y;
	}
	ans.x /= n, ans.y /= n, ans.w = calc(ans.x,ans.y);
	sa();
	cout<<fixed<<setprecision(3)<<ans.x<<" "<<ans.y<<"\\n";
	return 0;
}

以上是关于luogu1337JSOI2004平衡点 / 吊打XXX(模拟退火)的主要内容,如果未能解决你的问题,请参考以下文章

P1337 [JSOI2004]平衡点 / 吊打XXX

P1337 [JSOI2004]平衡点 / 吊打XXX

P1337 [JSOI2004]平衡点 / 吊打XXX

P1337 [JSOI2004]平衡点 / 吊打XXX

洛谷P1337 [JSOI2004]平衡点 / 吊打XXX(模拟退火)

洛谷P1337 [JSOI2004]平衡点 / 吊打XXX(模拟退火)