洛谷“新创无际夏日公开赛—-幻想乡的西瓜”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;
}

分享至ヾ(≧∇≦*)ゝ:
分类: 所有

发表评论

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

你是机器人吗? =。= *