ZOJ 3913 Bob wants to pour water (计算几何+二分)

1.题目链接

传送门

2.题意:

给定一个 宽为 w ,长为 l ,高为 h ,的长方体,里面有一些小长方体和球体,往里面注入体积为 v 的水,求最后水平面的高度。

3.分析:

1.大体的思路

很明显我们只需要二分答案就可以了,主要的就是求球缺的体积了。

2.球缺的体积的求法

ZOJ 3913 Bob wants to pour water (计算几何+二分)_第1张图片
然后我们把他看 许多个圆柱的体积的和,做一个定积分就可以了。
b0π[R2(Rx)2)]dx=πb2(Rb/3)

Code

#include <bits/stdc++.h>

using namespace std;

const int maxn = 1e5+10;

const double pi = acos(-1.0);

const double eps = 1e-10;

struct circle {
    double h,r;
    void input() {
        scanf("%lf%lf",&h,&r);
        h-=r;
    }
    double calc(double tmp) {
        double d = max(0.0, tmp - h);
        d = min(2 * r, d);
        return pi * (r * d * d - d * d * d / 3);
    }
} c[maxn];

struct cube {
    double h,a,b,c;
    void input() {
        scanf("%lf%lf%lf%lf",&h,&a,&b,&c);
        h-=c/2;
    }
    double calc(double tmp) {
        double d = max(0.0, tmp - h);
        d = min(d, c);
        return a * b * d;
    }
} s[maxn];

double w,l,v;
int n,m;

int dcmp(double a) {
    if(fabs(a)<=eps) return 0;
    if(a<0) return -1;
    return 1;
}

double check(double height) {
    double tot = w*l*height;
    for(int i=0; i<n; i++) {
        tot-=s[i].calc(height);
    }
    for(int i=0; i<m; i++) {
        tot-=c[i].calc(height);
    }
    return tot+eps>=v;
}

int main() {
    int t;
    scanf("%d",&t);
    while(t--) {
        scanf("%lf%lf%lf%d%d",&w,&l,&v,&n,&m);
        for(int i=0; i<n; i++)
            s[i].input();
        for(int i=0; i<m; i++)
            c[i].input();
        double l=0,r=10000000000.0;
        while(l+eps<r) {
            double mid = (l+r)/2.0;
            if(check(mid)) r=mid;
            else l=mid;
        }
        printf("%.6lf\n",r);
    }
    return 0;
}

你可能感兴趣的:(ZOJ,球缺体积)