历届试题 农场阳光
问题描述
X星球十分特殊,它的自转速度与公转速度相同,所以阳光总是以固定的角度照射。
最近,X星球为发展星际旅游业,把空间位置出租给Y国游客来晒太阳。每个租位是漂浮在空中的圆盘形彩云(圆盘与地面平行)。当然,这会遮挡住部分阳光,被遮挡的土地植物无法生长。
本题的任务是计算某个农场宜于作物生长的土地面积有多大。
最近,X星球为发展星际旅游业,把空间位置出租给Y国游客来晒太阳。每个租位是漂浮在空中的圆盘形彩云(圆盘与地面平行)。当然,这会遮挡住部分阳光,被遮挡的土地植物无法生长。
本题的任务是计算某个农场宜于作物生长的土地面积有多大。
输入格式
输入数据的第一行包含两个整数a, b,表示某农场的长和宽分别是a和b,此时,该农场的范围是由坐标(0, 0, 0), (a, 0, 0), (a, b, 0), (0, b, 0)围成的矩形区域。
第二行包含一个实数g,表示阳光照射的角度。简单起见,我们假设阳光光线是垂直于农场的宽的,此时正好和农场的长的夹角是g度,此时,空间中的一点(x, y, z)在地面的投影点应该是(x + z * ctg(g度), y, 0),其中ctg(g度)表示g度对应的余切值。
第三行包含一个非负整数n,表示空中租位个数。
接下来 n 行,描述每个租位。其中第i行包含4个整数xi, yi, zi, ri,表示第i个租位彩云的圆心在(xi, yi, zi)位置,圆半径为ri。
第二行包含一个实数g,表示阳光照射的角度。简单起见,我们假设阳光光线是垂直于农场的宽的,此时正好和农场的长的夹角是g度,此时,空间中的一点(x, y, z)在地面的投影点应该是(x + z * ctg(g度), y, 0),其中ctg(g度)表示g度对应的余切值。
第三行包含一个非负整数n,表示空中租位个数。
接下来 n 行,描述每个租位。其中第i行包含4个整数xi, yi, zi, ri,表示第i个租位彩云的圆心在(xi, yi, zi)位置,圆半径为ri。
输出格式
要求输出一个实数,四舍五入保留两位有效数字,表示农场里能长庄稼的土地的面积。
样例输入
10 10
90.0
1
5 5 10 5
90.0
1
5 5 10 5
样例输出
21.46
样例输入
8 8
90.0
1
4 4 10 5
90.0
1
4 4 10 5
样例输出
1.81
样例输入
20 10
45.0
2
5 0 5 5
8 6 14 6
45.0
2
5 0 5 5
8 6 14 6
样例输出
130.15
前言:这道题应该是难度很大的题,经过两小时的折腾之后,并在网上找答案的过程也证明了这道题的难度(目前没找到正确的代码),下面我的代码当精度给的很高的时候可以正确的求出答案,对于规模小的数据可以在1s内给出答案,但是测试数据一般都很***钻,所以大部分的测试数据都是超时的。
当我把精度设小的时候,虽然大部分数据可以很快给出答案,但是答案只是接近正确的答案,所以下面的代码只是给出我的代码的思路,并没有正确的把这道题解决。
思路:因为题目的目的是求没有被云层遮挡的面积,而云层在地上留下的阴影是圆,那么我们求出每个云层在地上的圆心,并把整个土地划分很小的块(比如一平方米划分为100*100=10000份)(涉及到精度),计算每个块到各个圆的圆心的距离,如果这个距离都大于每个圆的半径,那么这个点就是没被遮挡的土地,否则就是被遮挡的,
计算没被遮挡的土地占所有的土地的百分比,进而计算出面积。
代码如下
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 int main() 5 { 6 int a,b; 7 cin >> a >> b; 8 double g; 9 cin >> g; 10 g=g*3.1415926/180;//把角度化为弧度,因为计算机里面sin,cos的参数为弧度。 11 int n; 12 cin >> n; 13 int array[n][4]; 14 memset(array,0,sizeof(array)); 15 for(int i=0;i<n;i++){ 16 cin >> array[i][0]>>array[i][1]>>array[i][2]>>array[i][3]; 17 } 18 double array2[n][2]; 19 memset(array2,0,sizeof(array2)); 20 for(int i=0;i<n;i++){//求每个圆的圆心 21 array2[i][0]=array[i][0]+array[i][2]*(cos(g)/sin(g)); 22 array2[i][1]=array[i][1]; 23 } 24 int sum1=0; 25 int sum2=0; 26 int jingdu=200;//此时精度为200(即每一个单位在划分200份),精度越大,正确率越高,但是大的数据肯定超时。 27 for(int i=0;i<a*jingdu;i++){ 28 for(int j=0;j<b*jingdu;j++){ 29 int flag=0; 30 for(int k=0;k<n;k++){ 31 double s=sqrt((i-array2[k][0]*jingdu)*(i-array2[k][0]*jingdu)+(j-array2[k][1]*jingdu)*(j-array2[k][1]*jingdu)); 32 if(s<=array[k][3]*jingdu){//求出该点到每个阴影的距离并和半径做比较,在阴影内,标志位被修改。 33 flag=1; 34 break; 35 } 36 37 } 38 if(flag==0){ 39 sum1++;//在阴影外的点 40 }else{ 41 sum2++; 42 } 43 } 44 } 45 cout << sum1 << endl; 46 double so= sum1*1.0/(jingdu*jingdu); 47 cout << setiosflags(ios::fixed)<<setprecision(2) ; 48 cout << so; 49 return 0; 50 }
总之该代码可以在较短的时间内求出近似解(当jingdu比较小的时候),但是如果要求精确解,则参数jingdu越大越好,结果是大部分数据大大超时,也许某天计算机计算速度足够快,这个解法也许就不存在超时的问题了吧orz。
下面是蓝桥杯练习系统给的提示
感觉就是在考数学,还没总结出规律。
有正确的解法或者思路的大佬请在下面留言。
**************************************************************************************************
后记
总结下代码里面两个小知识点
1:c++里面三角函数的参数是弧度,所以角度要换成弧度,公式为PI*角度/180
2:保留两位小数cout << setiosflags(ios::fixed)<<setprecision(2) ;
作者:你的雷哥
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文连接,否则保留追究法律责任的权利。