問題描述
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) ;