牛客多校第二场 B 题题解

light

https://ac.nowcoder.com/acm/contest/33187/B

B Light

B 题题意:给定一个凸多边形 {Cn}\{C_n\},在这一多边形向内延申 ww 的范围有一堵高为 hh 的墙,墙内多边形记为 CC'。现在在点 L(x,y,z)L(x,y,z) 处有一点光源,问该点光源照射到 CC' 的面积。n2×103n \leq 2\times 10^3

解法:对于凸多边形,向内缩 ww 可以使用半平面交:对于每条原多边形的边 (P,v)(P,\vec{v}),向内缩 ww 即是一个半平面 (P+wvv,v)\left(P+\dfrac{w}{|\vec{v'}|}\vec{v'},\vec{v}\right),其中 v\vec{v'} 表示 v\vec{v} 沿逆时针方向旋转 π2\dfrac{\pi}{2} 所得向量。

对于点光源照射部分,对于每堵墙的限制,只需要判断 LL 是在该墙 (P,v)(P,\vec{v}) 的左侧还是右侧。若为左侧,则墙无法阻拦光线;否则墙就会有阻挡作用。只有当 z>hz>h 时才会有光射入该半平面,延申长度可以使用相似三角形求出——该操作就是继续对该内缩的凸多边形继续内缩,只是这次内缩距离是由点光源到墙的距离给出的。

因而使用半平面交即可轻松求出面积。总复杂度 O(n2)\mathcal O(n^2)

只放上主函数:

int main()
{
    int t, n;
    double h, x, y, z, w;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d%lf%lf", &n, &h, &w);
        auto nx = [&](int x)
        {
            return (x + 1) % n;
        };
        vector<Point> que(n);
        for (int i = 0; i < n;i++)
            scanf("%lf%lf", &que[i].x, &que[i].y);
        scanf("%lf%lf%lf", &x, &y, &z);
        Convex out = convexhull(que);
        vector<Line> shrink(n);
        for (int i = 0; i < n;i++)
        {
            shrink[i].v = out.p[nx(i)] - out.p[i];
            auto dir = out.p[nx(i)] - out.p[i];
            auto verdir = (Point){-dir.y, dir.x};
            shrink[i].p = out.p[i] + verdir * (w / verdir.len());
        }
        auto inner = halfinter(shrink);
        if (inner.size() <= 2)
        {
            printf("0\n");
            continue;
        }
        auto newinner = inner;
        Point light = (Point){x, y};
        bool flag = 0;
        auto ori = halfint_to_convex(inner);
        double outer = ori.area();
        for (auto i : inner)
        {
            auto res = i.toleft(light);
            if (res == -1)
            {
                if (z <= h)
                {
                    flag = 1;
                    break;
                }
                double light_to_wall = i.dis(light);
                double verdis = light_to_wall * h / (z - h);
                Point verdir = (Point){-i.v.y, i.v.x};
                Line nowline;
                nowline.v.x = i.v.x;
                nowline.v.y = i.v.y;
                nowline.p = i.p + verdir * (verdis / verdir.len());
                newinner.push_back(nowline);
            }
        }
        if(flag)
        {
            printf("0\n");
            continue;
        }
        auto ans = halfinter(newinner);
        auto shade = halfint_to_convex(ans).area();
        printf("%.10lf\n", shade);
    }
    return 0;
}
全部评论

相关推荐

11-27 12:43
已编辑
门头沟学院 C++
点赞 评论 收藏
分享
死在JAVA的王小美:哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈,我也是,让我免了一轮,但是硬气拒绝了
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务