[poj2194]Stacking Cylinders--计算几何

题目描述

Cylinders (e.g. oil drums) (of radius 1 foot) are stacked in a rectangular bin. Each cylinder on an upper row rests on two cylinders in the row below. The cylinders in the bottom row rest on the floor. Each row has one less cylinder than the row below.

这里写图片描述

This problem is to write a program to compute the location of the center of the top cylinder from the centers of the cylinders on the bottom row. Computations of intermediate values should use double precision.

Input

Each data set will appear in one line of the input. An input line consists of the number, n, of cylinders on the bottom row followed by n floating point values giving the x coordinates of the centers of the cylinders (the y coordinates are all 1.0 since the cylinders are resting on the floor (y = 0.0)). The value of n will be between 1 and 10 (inclusive). The end of input is signaled by a value of n = 0. The distance between adjacent centers will be at least 2.0 (so the cylinders do not overlap) but no more than 3.4 (cylinders at level k will never touch cylinders at level k – 2).

Output

The output for each data set is a line containing the x coordinate of the topmost cylinder rounded to 4 decimal places, a space and the y coordinate of the topmost cylinder to 4 decimal places. Note: To help you check your work, the x-coordinate of the center of the top cylinder should be the average of the x-coordinates of the leftmost and rightmost bottom cylinders.

Sample Input

4 1.0 4.4 7.8 11.2
1 1.0
6 1.0 3.0 5.0 7.0 9.0 11.0
10 1.0 3.0 5.0 7.0 9.0 11.0 13.0 15.0 17.0 20.4
5 1.0 4.4 7.8 14.6 11.2
0

Sample Output

6.1000 4.1607
1.0000 1.0000
6.0000 9.6603
10.7000 15.9100
7.8000 5.2143

题解

题目的大概意思就是给你一排半径为1的圆的圆心坐标,要你一层一层往上叠半径为一的圆,问你最上面那个圆的圆心坐标是多少。

介于网上的题解大多都是通过暴力计算得来的,代码也比较的长,于是我就发一篇比较巧妙的方法。

首先,我们可以考虑从左往右已经加了m个圆了,我们再加第m+1个圆的时候旧的顶端圆心和新的顶端圆心的横纵坐标差,如果知道了这个这道题目就迎刃而解了。但是怎么求呢?先看一下这张图:
[poj2194]Stacking Cylinders--计算几何_第1张图片
首先,图片中出现的两个由四个圆心构成的四边形肯定是菱形,于是 a//b//c a / / b / / c ,且 a=b=c a = b = c ,然后我们可以将旧的顶端圆心向 y y 轴方向作垂线,将新的顶端圆心向 x x 轴作垂线,这样就构成了一个直角三角形,且两条直角边正好是旧新圆心的横纵坐标差。

我们在底层第m个圆和第m+1个圆也做类似的连线,也会构成一个直角三角形。如图中的绿色标志代表的。不难看出,两个三角形是全等的(三条边都平行且 a=c=2 a = c = 2 )。

所以我们只要求出下面这个三角形的两条直角边的长度就可以了,我们用 a[i] a [ i ] 来表示第i个底层圆的圆心。首先下面那个直角边很好算,因为 cd c 和 d 对称,所以下面那条边的边的长度就是 a[m+1]a[m]2 a [ m + 1 ] − a [ m ] 2 ,知道这个,右边的这个就更好算了, 22(a[m+1]a[m]2)2 2 2 − ( a [ m + 1 ] − a [ m ] 2 ) 2

那么求出上面这个,这道题就非常简单了,圆心的 x x 坐标是:

X=a[1]+a[2]a[1]2+a[3]a[2]2+......+a[n]a[n1]2=a[1]+a[n]2 X = a [ 1 ] + a [ 2 ] − a [ 1 ] 2 + a [ 3 ] − a [ 2 ] 2 + . . . . . . + a [ n ] − a [ n − 1 ] 2 = a [ 1 ] + a [ n ] 2

y y 坐标是:
Y=1+i=1n122(a[i+1]a[i]2)2 Y = 1 + ∑ i = 1 n − 1 2 2 − ( a [ i + 1 ] − a [ i ] 2 ) 2

这样就可以用很短的代码写出来这道题了,也不用算那么多了。。。

这道题目就讲完了,下面放代码:

#include
#include
#include
#include
#include
#define maxn 20
using namespace std;
int n;
double a[maxn];
int main()
{
    while(~scanf("%d",&n)&&n)
    {
        for(int i=1;i<=n;i++)  scanf("%lf",&a[i]); 
        double ans1,ans2=1.0;
        sort(a+1,a+n+1);
        ans1=(a[n]+a[1])/(double)2;
        for(int i=2;i<=n;i++)
        {
            double tmp=(a[i]-a[i-1])/2;
            ans2+=sqrt((double)4-tmp*tmp);
        }
        printf("%.4lf %.4lf\n",ans1,ans2);
    } 
    return 0;
}

谢谢大家!!

你可能感兴趣的:(计算几何)