• 历届试题 农场阳光


    问题描述

      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) ;

  • 相关阅读:
    哲学家进餐
    文件系统
    文件读写原理(转)
    数据库join种类
    http与https区别
    数字证书(转)
    B. Rebranding
    扩展欧几里德算法、证明及其应用
    CodeForces 7C Line
    UVALive 7147 World Cup
  • 原文地址:https://www.cnblogs.com/henuliulei/p/10502220.html
Copyright © 2020-2023  润新知