历届试题 农场阳光

问题描述

  X星球十分特殊,它的自转速度与公转速度相同,所以阳光总是以固定的角度照射。
  最近,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。
输出格式
  要求输出一个实数,四舍五入保留两位有效数字,表示农场里能长庄稼的土地的面积。
样例输入
10 10
90.0
1
5 5 10 5
样例输出
21.46
样例输入
8 8
90.0
1
4 4 10 5
样例输出
1.81
样例输入
20 10
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) ;

posted @ 2019-03-09 17:50  你的雷哥  阅读(1520)  评论(0编辑  收藏  举报