JSOI2004 平衡点

队友看到一道貌似是计算几何的题目,遂搞之……

给出桌面上的n个洞的坐标(xi, yi),每个洞下面有一个重物,重物质量为pi。重物上面有一条足够长的绳子穿过孔,所有的绳子系在一个结上。绳结足够大,不会从孔里掉到桌面下,同时桌面足够高,重物不会触地。

一开始以为有什么神奇的数学规律,列方程……发现方程带着一堆三角函数/根号根本没法解……

后来发现这题其实像是大模拟,先假定绳结在某个位置,求绳结在这个位置上受到的力,然后根据力的大小和方向调整绳结的位置。当合力的大小足够小的时候,就是答案了。

//貌似很多求不出精确解/解析解的问题都可以用类似的鬼畜方法解决,最后得到一个近似解


题目链接:

http://www.luogu.org/problem/show?pid=1337#


#include <iostream>
#include <cstdio>
#include <cmath>
#include <ctime>

using namespace std;

class Point {
public:
	double x, y;

	Point(double _x = 0.0, double _y = 0.0) :x(_x), y(_y) {};

	double distTo(Point p) {
		return sqrt((x - p.x)*(x - p.x) + (y - p.y)*(y - p.y));
	}

	double length() {
		return this->distTo(Point(0, 0));
	}

};

Point p[1023];
double w[1023];

Point p0, px;
int n;

Point f;

const double eps = 1e-7;

double k = 100;

int sgn(double a) {
	return fabs(a) < eps ? 0 : (a < 0 ? -1 : 1);
}


void iter() {
	double dis;
	for (int i = 0; i < n; i++) {
		dis = p0.distTo(p[i]);
		if (sgn(dis) == 0) continue;
		double _cos = (p[i].x - p0.x) / dis,
			_sin = (p[i].y - p0.y) / dis;
		f.x += w[i] * _cos;
		f.y += w[i] * _sin;
	}
}
        
int main() {

	scanf("%d", &n);

	for (int i = 0; i < n; i++) {
		scanf("%lf%lf%lf", &p[i].x, &p[i].y, &w[i]);
		px.x += p[i].x;
		px.y += p[i].y;
	}
	px.x /= n;
	px.y /= n;

	for (int i = 0; i < 90; i++) {
		p0 = px;
		for (int j = 0; j < 100; j++) {
			f = Point(0, 0);
			iter();

			if (f.length() <= k) break;
			p0.x += k*(f.x / f.length());
			p0.y += k*(f.y / f.length());
		}
		px = p0;
		k *= 0.4;
	}

	printf("%.3lf %.3lf\n", p0.x, p0.y);

	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值