1. 程式人生 > 其它 >[模板]模擬退火 / 洛谷 P1337 [JSOI2004]平衡點

[模板]模擬退火 / 洛谷 P1337 [JSOI2004]平衡點

目錄
[模板]模擬退火 / 洛谷 P1337 [JSOI2004]平衡點

題目

題目描述

如圖:有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

程式碼+註釋

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstdlib>
unsigned seed;

int read() {
	int re = 0;
	char c = getchar();
	bool negt = false;
	while(c < '0' || c > '9')
		negt |= (c == '-') , c = getchar();
	while(c >= '0' && c <= '9')
		re = (re << 1) + (re << 3) + c - '0' , c = getchar();
	seed *= re;
	return negt ? -re : re;
}

const int N = 10010;
struct NodeClass {
	int x , y , m;
}node[N];

int n;
double ansx , ansy;
double minEp = 1e18;//Ep:重力勢能的縮寫,minEp即最小的重力勢能,也就是(搜過的答案中)最穩定的狀態,最趨近平衡的狀態
const double delta_t = 0.993;
const double originT = 3000;//原溫度

double calc_Ep(double nowx , double nowy) {
	double sum = 0;
	for(int i = 1 ; i <= n ; i++) {
		double delx = nowx - node[i].x , dely = nowy - node[i].y;
		sum += std::sqrt(delx * delx + dely * dely) * node[i].m;//求總重力勢能,嚴格來說Ep=mgh,這裡省略重力加速度g
	}
	return sum;
}
void simulate_anneal() {
	double x = ansx , y = ansy;
	double t = originT;
	while(t > 1e-14) {
		double nowx = ansx + (rand() * 2 - RAND_MAX) * t;
		double nowy = ansy + (rand() * 2 - RAND_MAX) * t;
		double nowEp = calc_Ep(nowx , nowy);
		double DE = nowEp - minEp;
		if(DE < 0) {//新答案更優
			ansx = x = nowx , ansy = y = nowy;
			minEp = nowEp;
		}
		else if(exp(-DE / t) * RAND_MAX > rand()) {//隨機決定是否選擇不那麼優的答案
			x = nowx , y = nowy;
		}
		t *= delta_t;
	}
}
int main() {
	n = read();
	for(int i = 1 ; i <= n ; i++)
		node[i].x = read() , node[i].y = read() , node[i].m = read();
	
	std::srand(seed);
	
	for(int i = 1 ; i <= 4 ; i++)//多跑幾次
		simulate_anneal();
	printf("%.3f %.3f" , ansx , ansy);
	return 0;
}