POJ 1031--Fence

题意

题目意思是,在一个平面上,有一个由若干个栅栏围成的多边形。同时还有一个灯,灯可能在多边形里面或者外面(反正不在栅栏上),已知在空间中任何一点受到的光强为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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值