洛谷 “新创无际夏日公开赛—-幻想乡的西瓜”T3

题意:将球体沿俯视图的两条半径切去一个扇形,求正视图中球的内部部分占总可视面积的百分比,如图为俯视图,正视图面向 0°的位置。两条半径的极角为 a,b∈[0,360] 的整数,从若 x∈[a,b] 则 x 对应的半径已被切去。如图:

此题的分类讨论较多。设两条半径的极角分别为 a,b(a,b∈[0,360]):

则可以按 a,b 所在的四个象限及 a,b 的大小关系分为 20 类。
下面讨论对于某一分类,如何确定面积。由于切面为两个半圆,所以在空间中它也是两个圆。

引理 1:圆在空间中对于任意平面的平行投影为椭圆或线段。

引理 2:设一椭圆的长短轴长度分别为 p,q, 则 $S=\pi pq$

因此,我们可以利用引理 1、2 求出切面的正视图面积,求出面积差,进而求出答案。

需要注意的是,某些情况下全面积会由于切去部分而减少,如 a=0,b=180 的情况。

#include <iostream>
#include <cstdio>
#include <cmath>
#define pi 3.1415926535
using namespace std;
double dutohu(int x){return pi/180*x;}
double getarea(int a,int b)
{
    double s1,s2;
    s1=abs(pi*1*cos(dutohu(90-a)));
    s2=abs(pi*1*cos(dutohu(90-b)));
    if(a>=0&&a<90){
        if(b>=0&&b<a)return (s2/2)/(s1/2);
        else if(b>=a&&b<90)return (s2/2-s1/2)/pi;
        else if(b>=90&&b<180)return max(s2/2-s1/2,0.0)/(pi/2+max(s2/2,s1/2));
        else return 0;
    }
    else if(a>=90&&a<180){
        if(b>=0&&b<90)return s2/2/(pi/2);
        else if(b>=90&&b<a)return 1;
        else return 0;
    }
    else if(a>=180&&a<270){
        if(b>=0&&b<90)return (s1/2+s2/2)/(s1/2+pi/2);
        else if(b>=90&&b<a)return 1;
        else if(b>=a&&b<270)return 0;
        else return max(s1/2-s2/2,0.0)/(pi/2+max(s1/2,s2/2));
    }
    else if(a>=270&&a<360){
        if(b>=0&&b<90)return (s1+s2)/pi/2;
        else if(b>=90&&b<180)return (s1/2+s2/2)/(pi/2+s2/2);
        else if(b>=180&&b<270)return (s1/2)/(pi/2);
        else if(b>=270&&b<a)return s1/s2;
        else return (s1/2-s2/2)/pi;
    }
}
int main(){
    int t,a,b;
    scanf("%d",&t);
    for(int w=1;w<=t;w++){
        scanf("%d%d",&a,&b);
        printf("%.1f",getarea(a,b)*100);
        puts("%");
    }
    return 0;
}
分类: 文章

0 条评论

发表回复

Avatar placeholder

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