平衡点——搜索

平衡点——搜索


题目来源

洛谷P1337


题目描述

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

说明
江苏省选


解题报告

我们可以确定一个原点,将所有的力在这个原点上正交分解,最终我们可以得到所有的力的一个合力,而真正的平衡点一定在合力所指向的方向

每当分解得到一个合力之后,将原点在合力的方向上位移一定的距离。每当原点位移的方向发生了改变的,缩小以后操作的位移距离。例如:上次操作是将原点向 x 轴正方向移动,而当前移动是将原点像 x 轴负方向上移动,这说明原点的横坐标一定在这两次假设的原点的横坐标中间,因此我们缩小以后原点移动的距离。

当两次移动的坐标差在一定的范围之内时,说明我们得到了解,输出即可(注意:规定的范围一定要小于题目所要求的精度范围)


源代码

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

#define abs(x) ((x) >= 0 ? (x) : (-(x)))

using namespace std;

int n;
double x, y;

bool XF = true, YF = true;//原点移动的方向 true 代表正方向,false 代表负方向

struct Position {
    int x;
    int y;
    int power;
} positions[1005];

void solve(double move) {
    double X, Y, temp;
    X = Y = 0;

    for (int i = 1; i <= n; i++) {
        temp = sqrt((x - positions[i].x) * (x - positions[i].x) + (y - positions[i].y) * (y - positions[i].y));//记录该点到原点的欧几里得距离
        if (temp == 0)//判断是否与原点重合
            continue;
        //若不重合则进行正交分解
        X += positions[i].power / temp * (positions[i].x - x);
        Y += positions[i].power / temp * (positions[i].y - y);
    }

    temp = sqrt(X * X + Y * Y);//计算正交分解后的合力
    //将原点在合力方向上位移一定距离
    x += move / temp * X;
    y += move / temp * Y;
}

int main() {
    freopen("in.txt", "r", stdin);

    scanf("%d", &n);

    for (int i = 1; i <= n; i++)
        scanf("%d%d%d", &positions[i].x, &positions[i].y, &positions[i].power);
    //move:移动的步长  tx ty 保存移动前的原点的位置
    double move = 5000, tx, ty;

    while (true) {
        //记录移动前原点的位置
        tx = x;
        ty = y;

        solve(move);//按照步长移动原点

        if (abs(tx - x) < 0.00001 && abs(ty - y) < 0.00001)//判断是否满足精度要求
            break;

        if ((XF != (x > tx)) || (YF != (y > ty))) {//若移动方向发生改变
            //记录移动方向
            XF = !x > tx;
            YF = !y > ty;
            move = move * 0.9;//缩小移动距离
        }
    }

    printf("%.3f %.3f", x, y);

    return 0;
}
发布了33 篇原创文章 · 获赞 16 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/Fine_rose/article/details/78210657