队友看到一道貌似是计算几何的题目,遂搞之……
给出桌面上的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;
}