[JSOI2004]平衡点

题目描述

如图:有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,y方向上分力的和,求出合力,再移动平衡点
首先定下一个尺度k,每次平衡点移动以k为单位。如果尺度过大了,则缩小尺度,缩小量0.4~0.99随意
如果这时的合力大于这个尺度,我们就对这个已经设定好的平衡点进行调整,让它更加接近真实的平衡点。
当合力在尺度以内或者调整一定次数以后,我们减小尺度,再次进行调整。
这道题用到了一种调整思想,即不断逼近正解
ps:几个月后回来发现这其实是一道爬山算法(或模拟退火)题
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 using namespace std;
 7 int n;
 8 double x[1001],y[1001],w[1001],k,xa,ya,xx,yy,fx,fy,d;
 9 int main()
10 {int i,j,p;
11     cin>>n;
12     for (i=1;i<=n;i++)
13     {
14         scanf("%lf%lf%lf",&x[i],&y[i],&w[i]);
15     }
16     k=100;
17     xa=0;ya=0;
18      for (i=1;i<=100;i++)
19      {
20          xx=xa;yy=ya;
21          for (p=1;p<=200;p++)
22          {
23              fx=0;fy=0;
24              for (j=1;j<=n;j++)
25              {
26                  d=sqrt((xx-x[j])*(xx-x[j])+(yy-y[j])*(yy-y[j]));
27                  if (d) 
28                  {
29                  double dx=x[j]-xx,dy=y[j]-yy;
30                  fx+=dx/d*w[j];fy+=dy/d*w[j];
31                  }
32             }
33             d=sqrt(fx*fx+fy*fy);
34             if (d<=k) break;
35             xx+=fx/d*k;yy+=fy/d*k;
36         }
37         xa=xx;ya=yy;
38         k*=0.4;
39      }
40     printf("%.3lf %.3lf\n",xa,ya);
41 }

 

posted @ 2017-07-31 16:49  Z-Y-Y-S  阅读(364)  评论(0编辑  收藏  举报