[WF2015]Cutting Cheese 题解

[WF2015]Cutting Cheese 题解

题目地址:UVa:UVa Online Judge、洛谷:【UVA1712】Cutting Cheese – 洛谷

题目描述

原题面参见UVa/vjudge。
给你一个100*100*100的大方块,里面有若干球形空缺,要求切成s个体积相同的小方块,求每一块的厚度。

题解

简单的计算几何。
我们考虑球形体积和球缺体积的算法
\begin{aligned} V_{\text{ball}} &= \frac{4}{3} \pi r^3 \\ V_{\text{cap}} &= \pi h^2 (r - \frac{h}{3}) \end{aligned}
对于每一块,我们二分计算它与之前所有块加起来的厚度(因为这样只需要考虑切面的球缺),每次计算块体积的时候遍历球体,如果完全包含减体积,如果部分包含减球缺体积,

代码

// Code by KSkun, 2018/3
#include <cstdio>
#include <cmath>

typedef long double LD;

const int MAXN = 10005;
const LD PI = acos(-1), EPS = 1e-12;

inline LD getballv(LD r) {
    return r * r * r * 4 / 3 * PI;
}

inline LD getballvq(LD r, LD h) {
    return PI * (3 * r - h) * h * h / 3;
}

int n, s;
LD z[MAXN], r[MAXN], len[MAXN], v;

inline LD getblockv(LD l) {
    LD res = l * 100 * 100;
    for(int i = 1; i <= n; i++) {
        if(z[i] + r[i] <= l) {
            res -= getballv(r[i]);
        } else if(z[i] - r[i] < l) {
            res -= getballvq(r[i], r[i] - z[i] + l);
        }
    }
    return res;
}

inline LD cal(LD v) {
    LD l = 0, r = 100, mid;
    while(r - l > EPS) {
        mid = (l + r) / 2;
        if(getblockv(mid) <= v) l = mid; else r = mid;
    }
    return l;
}

int main() {
    while(scanf("%d%d", &n, &s) != EOF) {
        v = 100 * 100 * 100;
        for(int i = 1; i <= n; i++) {
            scanf("%Lf%*d%*d%Lf", &r[i], &z[i]);
            r[i] *= 0.001; z[i] *= 0.001;
            v -= getballv(r[i]);
        }
        for(int i = 1; i <= s; i++) {
            len[i] = cal(i * v / s);
        }
        for(int i = 1; i <= s; i++) {
            printf("%.10Lf\n", len[i] - len[i - 1]);
        }
    }
    return 0;
}


发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据