P1337 [JSOI2004]平衡点 / 吊打XXX

题目描述

如图:有n个重物,每个重物系在一条足够长的绳子上。每条绳子自上而下穿过桌面上的洞,然后系在一起。图中X处就是公共的绳结。假设绳子是完全弹性的(不会造成能量损失),桌子足够高(因而重物不会垂到地上),且忽略所有的摩擦。

问绳结X最终平衡于何处。

注意:桌面上的洞都比绳结X小得多,所以即使某个重物特别重,绳结X也不可能穿过桌面上的洞掉下来,最多是卡在某个洞口处。

输入格式

文件的第一行为一个正整数n(1≤n≤1000),表示重物和洞的数目。接下来的n行,每行是3个整数:Xi.Yi.Wi,分别表示第i个洞的坐标以及第 i个重物的重量。(-10000≤x,y≤10000, 0<w≤1000 )

输出格式

你的程序必须输出两个浮点数(保留小数点后三位),分别表示处于最终平衡状态时绳结X的横坐标和纵坐标。两个数以一个空格隔开。

输入输出样例

输入

3
0 2
2 4
1 3

输出

2

分析

应该算紫题里比较简单的一道了,虽然是一道模拟退火的板子题但是我不会,但是直接正交分解移动一点就更新一点长度还是很简单的

程序

#include <bits/stdc++.h>

#define Enter puts("")
#define Space putchar(' ')

using namespace std;

typedef long long ll;
typedef unsigned long long Ull;
typedef double Db;

inline ll Read()
{
    ll Ans = 0;
    char Ch = getchar() , Las = ' ';
    while(!isdigit(Ch))
    {
        Las = Ch;
        Ch = getchar();
    }
    while(isdigit(Ch))
    {
        Ans = (Ans << 3) + (Ans << 1) + Ch - '0';
        Ch = getchar();
    }
    if(Las == '-')
        Ans = -Ans;
    return Ans;
}

inline void Write(ll x)
{
    if(x < 0)
    {
        x = -x;
        putchar('-');
    }
    if(x >= 10)
        Write(x / 10);
    putchar(x % 10 + '0');
}

int n , X[100001] , Y[100001] , Weight[100001];
Db x , y  , Length = 10000.0;

inline Db E(Db x)
{
    return x * x;
}

inline void Move(Db l)
{
    Db New_X = 0 , New_Y = 0 , G;
    for(int i = 1; i <= n; i++)
    {
        G = sqrt(E(X[i] - x) + E(Y[i] - y));
        if(G == 0)
            continue;
        New_X += Weight[i] / G * (X[i] - x);
        New_Y += Weight[i] / G * (Y[i] - y);
    }
    G = sqrt(New_X * New_X + New_Y * New_Y);
    x += l / G * New_X;
    y += l / G * New_Y;
}
int main()
{
    n = Read();
    for(int i = 1; i <= n; i++)
    {
        X[i] = Read();
        Y[i] = Read();
        Weight[i] = Read();
    }
    while(Length > 4e-4)
    {
        Move(Length);
        Length *= 0.9;    
    }
    printf("%.3f %.3f" , x , y);
    return 0;
}

 

posted @ 2020-12-18 23:23  Tenderfoot  阅读(106)  评论(0编辑  收藏  举报