HDU 5954 Do not pour out(二分+積分)

傳送門

You have got a cylindrical cup. Its bottom diameter is 2 units and its height is 2 units as well.
The height of liquid level in the cup is d (0 ≤ d ≤ 2). When you incline the cup to the maximal angle such that the liquid inside has not been poured out, what is the area of the surface of the liquid?
 

Input
The first line is the number of test cases. For each test case, a line contains a float-point number d.
 

Output
For each test case, output a line containing the area of the surface rounded to 5 decimal places.
 

Sample Input
4 0 1 2 0.424413182
 

Sample Output
0.00000 4.44288 3.14159 3.51241

題目大意:

有一個圓柱瓶子,高爲 2 , 底面直徑爲 2 ,現在瓶子裏有高爲 d(0d2) 的水,現在把瓶子傾斜到最大使水不露出來,求水面的面積。

解題思路:

二分底面,然後積分求面積和體積。
由高中學過的幾何知識可以知道:水面相當於對於一個很長的圓柱體傾斜的用刀切開,那麼這個切面就是一個完整的橢圓,當然如果不傾斜則得到特殊的橢圓——圓,如果水面經過杯底,那麼水面就是一個缺少一部分的橢圓,所以我們需要分開討論水面經過杯底和不經過杯底兩種情況。
那麼這兩種情況的d的臨界值是多少呢? 可以發現對於水剛到杯底的時候,有水和無水的部分各佔一半,所以分界點d=1;

1、水面不經過杯底d1
這裏寫圖片描述
這種情況如上圖所示,h+(2h)2=d , 所以h=2d2 ,那麼可以求出水面這個完整橢圓的長半徑a=22+(2h)22 ,而橢圓的短半經是b=1 ,所以水面面積爲S=PIab .

2、水面經過杯底d<1
這裏寫圖片描述

對於上圖中 mid 越大則水的體積越大,那麼我們可以根據體積二分mid 求出 mid 真實長,最後根據真實的 mid 求出水面的面積,可以知道二分範圍爲(0,2) 。每次我們需要根據當前 mid 求出水的體積,因爲水體不規則所以必須積分求水的體積。
積分:我們根據水的高度積分,如上圖所示利用 y 積分求體積,那麼我們需要根據 y 求出每個水體截面的長 t (類似於杯底的 mid ),求相似三角形 tmid=(2y)2t=(2y)mid2 ; 然後根據水截面長 t 求出當前水體截面的面積 S
可以知道水體截面爲一個扇形減去一個三角形組成,面積及體積如下圖所示:
這裏寫圖片描述
這裏寫圖片描述

求出真實的 mid 以後,那麼就可以求出水面的面積了。
這裏寫圖片描述

如上圖所示利用二分求出的 midlen=22+mid2 ,設水面與杯底的一個交點爲 (x,h)h=1(1mid)2 (由杯底水面交線所在圓很容易求出 h ),那麼 len=axx2a2+h2b2=1 ,解上面兩個方程 求得a=len1+flag1h2flagx=alen 可以發現 mid<1 時水面爲小半個橢圓,這時 x>0 ,所以 flag<0 , 反之mid<1 時,水面爲大半個橢圓,這時 x<0,flag>0

現在橢圓方程已求出,X 範圍 (x,a) (不是完整的橢圓),所以需要積分,如下圖所述:
這裏寫圖片描述

代碼:

#include <iostream>
#include <string.h>
#include <string>
#include <algorithm>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <map>
using namespace std;
typedef long long LL;
const int MAXN = 1e6+5;
const double PI = acos(-1);
const double eps = 1e-8;
const LL MOD = 1e9+7;

double cal2(double a,double x)
{
    double sum=x+sin(2*x)/2;
    return sum*a*0.5;
}
double area(double a,double x)
{
    double sum=cal2(a,0.5*PI);
    sum=sum-cal2(a,asin(x/a));
    return sum*2;
}
double cal(double x)
{
    double ans=sin(x)-sin(x)*sin(x)*sin(x)/3-x*cos(x);
    return ans;
}
double getV(double mid)
{
    double V=cal(0)-cal(acos(1-mid));
    V=V*(-2)/mid;
    return V;
}
int main()
{
    int T; cin>>T;
    while(T--)
    {
        double d; scanf("%lf",&d);
        if(d>1)
        {
            double h=2*d-2;
            double a=sqrt(4+(2-h)*(2-h))/2;
            printf("%.5f\n",PI*a);
            continue;
        }
        double l=0,r=2.0;
        for(int i=0;i<100;i++)
        {
            double mid=(l+r)/2;
            double V=getV(mid);
            if(V-PI*d>eps) r=mid;
            else l=mid;
        }
        double mid=l;
        int flag=1;
        if(mid<1) flag=-1;
        double len=sqrt(mid*mid+4);
        double h=sqrt(1-(1-mid)*(1-mid));
        double a=len/(1+flag*sqrt(1-h*h));
        double x=a-len;
        double res=area(a,x);
        printf("%.5f\n",res);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章