P1337-平衡點 / 吊打XXX

題目鏈接

題意:給出n條無限長繩子,繩子一端綁着重物,另一端彙集到一起成爲一個點,初始重物均位於桌面上,每個重物有一個座標(x,y),讓後讓重物自由落體,問整個系統平衡時繩子匯點位於何處?

分析:一道模擬退火的題目,我們首先對n個點求一下平均值,確定一下結果的大概位置。然後O(n)遍歷這n個點,將這n個點的拉力全部正交分解到x軸,y軸上,求x軸合力mgx,求y軸合力mgy。若mgx<0,將該點向正向移動,否則負向移動;對mgy的操作同理。

代碼:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5000;
const double eps=1e-14;
const double ep=0.0000005;
int n;
struct Node{
    double xi;
    double yi;
    double wi;
}p[maxn];
double xishu=0.00993;
double dis(double x,double y,double x0,double y0){
    return sqrt((x-x0)*(x-x0)+(y-y0)*(y-y0));
}
double fenjie(double a,double b){
    return a-b;
}
void SA(double x,double y,double w){
    double T=10000;
    while(T>eps){
        double temx=0,temy=0;
        for(int i=1;i<=n;i++){
            double L=dis(x,y,p[i].xi,p[i].yi);
            if(L==0)continue;				  //如果L==0,不能做分母,所以要continue 
            temx+=p[i].wi/L*fenjie(x,p[i].xi);//計算x軸上合力 
            temy+=p[i].wi/L*fenjie(y,p[i].yi);//計算y軸上合力 
        }
        if(abs(temx-0)<ep&&abs(temy-0)<ep)break;//優化 
        if(temx<0)								//如果合力向在x軸負向,點就向x軸正向移動 
            x+=(0-temx)*xishu;
        else
            x-=(temx-0)*xishu;
        if(temy<0)								//如果合力向在y軸負向,點就向y軸正向移動
            y+=(0-temy)*xishu;
        else
            y-=(temy-0)*xishu;
        T*=0.987;
        xishu*=0.9999;
    }
    printf("%.3f %.3f\n",x,y);
}
int main()
{
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>p[i].xi>>p[i].yi>>p[i].wi;
    
    double avex=0;
    double avey=0;
    double avew=0;
    for(int i=1;i<=n;i++){
        avex+=p[i].xi;
        avey+=p[i].yi;
    }
    avex/=n;
    avey/=n;
    for(int i=1;i<=n;i++)
        avew+=p[i].wi*dis(p[i].xi,p[i].yi,avex,avey);
        
    SA(avex,avey,avew);
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章