题意
题目意思是,在一个平面上,有一个由若干个栅栏围成的多边形。同时还有一个灯,灯可能在多边形里面或者外面(反正不在栅栏上),已知在空间中任何一点受到的光强为I=k/r(r为灯到这一点的连线在平面上投影的长度,其实就是说不考虑灯和这一点的高度),灯在栅栏上某一处宽为d的光强总和为I*|cosα|*d*h(α为灯到栅栏的垂线与灯到这一处的连线的夹角在平面上的投影),求灯在栅栏上的光强总和。
分析
一开始,我看错题了,以为距离是和夹角都是在空间里的,跑去求二重积分,其实都是在平面上的投影,这样只是一重积分。我们从上往下俯视,如下图:
那么在宽为d的栅栏上的光强为,那么整个栅栏上的光强就是对d的积分,再将d用α表示,得到:
显然本题的目标已经变成求灯到栅栏两端构成的夹角了。
由于光不能透过栅栏,所以对于后面的栅栏不必考虑。我们从灯连接一条线到栅栏上任意一点,让此点沿栅栏走一周,此线扫过的角度即是灯光能照射到栅栏上的范围。我们约定这一条线顺时针走动时,角度值正增长,角度值负增长。因此,如果灯在栅栏里面,这条线扫过的角度一定是360度。如果是在外面,最后扫过的角度会变为0,这时候设定两个值记录角度正向最大值和负向最小值,两者的差即为此线扫过的角度。
PS: 角度不会大于360度,所以当角度到达360度时,可以提前退出。
代码如下:
Memory: 248K Time: 32MS Length: 43LINES
#include <cmath>
#include <iomanip>
#include <iostream>
#define min(x,y) (((x) > (y)) ? (y) : (x))
#define max(x,y) (((x) < (y)) ? (y) : (x))
using namespace std;
const double pi = 3.1415926535898;
int main()
{
double k, h;
int count;
double array[101][2] = { 0 };
while (cin >> k >> h >> count)
{
for (int i = 0; i < count; ++i)
cin >> array[i][0] >> array[i][1];
array[count][0] = array[0][0];
array[count][1] = array[0][1];
double a, b;
a = atan2(array[0][1], array[0][0]);
double key = 1.0;
double sum = 0.0;
double maxsum = 0.0;
double minsum = 0.0;
int i = 1;
for (; i < count + 1; ++i, a = b)
{
b = atan2(array[i][1], array[i][0]);
double ang = abs(a - b);
ang = ang > pi ? 2 * pi - ang : ang;
if (a > b) key = (a - b < pi) ? 1.0 : -1.0;
else if (a < b) key = (b - a > pi) ? 1.0 : -1.0;
else key = 0.0;
sum += key * ang;
minsum = min(minsum, sum);
maxsum = max(sum, maxsum);
if (maxsum >= 2 * pi || minsum <= -2 * pi || (maxsum - minsum) >= 2 * pi) break;
}
cout << setprecision(2) << setiosflags(ios::fixed) << h * k * (i > count ? maxsum - minsum : 2 * pi) << endl;
}
return 0;
}