[Offer收割]编程练习赛2 hihocoder 1275 扫地机器人 (计算几何+模拟 比较烦)

37 篇文章 0 订阅
22 篇文章 0 订阅
时间限制:10000ms
单点时限:1000ms
内存限制:256MB

描述

小Ho最近买了一台扫地机器人用来代替他清扫实验室的卫生,扫地机器人有不同的尺寸,但是通常来说可以被视作一个M*M的正方形,扫地机器人仅能清扫被自己覆盖过的区域。

小Ho所在的实验室是一个多边形,任意两条边之间要么为垂直关系要么为平行关系。扫地机器人也仅能沿着这两个方向平移,不能旋转。实验室中的一些区域过于狭窄,所以对扫地机器人的大小就有了限制。

于是小Ho找到了你,给出实验室的地形和扫地机器人的大小,希望你能够判断给定的扫地机器人能否成功清扫实验室的每一块区域。

输入

每个输入文件包含多组测试数据,在每个输入文件的第一行为一个整数Q,表示测试数据的组数。

每组测试数据的第一行为两个正整数N和M,分别表示多边形的点数和机器人的大小。

接下来的N行,每行为两个整数X、Y,表示多边形的一个顶点。

多边形的顶点按照“顺时针”顺序给出,即从当前点前往下一个点时,多边形的“内部”在右侧方向,多边形的边均平行于坐标轴

对于20%的数据,满足0<=N<=200,1<=X、Y、M<=100

对于100%的数据,满足0<=N<=1000,1<=X、Y、M<=108

对于100%的数据,满足实验室可以由一个1*1的扫地机器人完成清扫。

对于100%的数据,满足Q<=5

输出

对于每组测试数据,如果机器人能够顺利完成任务,输出Yes,否则输出No。

样例提示

样例1(x轴正方向为向下,y轴正方向为向右):


样例3(x轴正方向为向下,y轴正方向为向右):

样例输入
3
6 2
0 0
0 2
2 2
2 3
3 3
3 0
6 2
0 0
0 3
3 3
3 5
5 5
5 0
8 2
0 0
0 2
1 2
1 3
3 3
3 1
2 1
2 0
样例输出
No
Yes
No

题目链接:http://hihocoder.com/problemset/problem/1275

题目分析:首先先%一下比赛时的满分选手,再吐槽一下直接找边平方最小与m方判断都能得70分的数据。。。

这题做了好久。。。中间过程比较烦,这题的大体思路是模拟,即从起点开始按输入顺序(顺时针)让机器人沿着多边形的内边走,每走一条边判断一下首先要处理知道一条边和下一个点怎么判断往哪个方向转的问题,先设三个点p1(当前线的起点),p2(当前线的终点),p3(下一个点)为了求方向我们把它们定义为空间中的三点p1(x1, y1, 0),p2(x2, y2, 0),p3(x3, y3, 0)

那么向量p1->p2表示为α=(x2-x1, y2-y1, 0),向量p2->p3表示为β=(x3-x2, y3-y2, 0),α×β (×为叉乘)得到f = (x1-x3)*(y2-y3)-(x2-x3)*(y1-y3)

根据右手定则,f>0时右转,f<0时左转。因此我们可以先算出机器人绕多边形一圈的整个转向过程,1表示右转,0表示左转,由于回到起点时起点也要判断,因此把第二个点作为最后一个点。由于我们是按照输入顺序即顺时针方向贴边内侧走,因此可以发现,每次到一个角时,如果是向右转则必定在内角,否则在外角,如下图:

之后对于每个角算出机器人所要占据的面积再枚举每一条线,判断是否有线穿过机器人,有则无解,不冲突的情况共8种,如下图:


开始用了骗分的那种思路做特判其实也是不对的,比如这种图形


短边为1,长边为2,显然用边长为2的机器人是可以全部打扫到的

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#define ll long long
using namespace std;
int const MAX = 1e3 + 5;
int n, m;
int dir[MAX]; //0左,1右

struct POINT
{
    int x, y;
}p[MAX];

struct LINE
{
    POINT s, e;
}l[MAX];

struct ROBOT
{
    int x1, y1, x2, y2;
};

int Dir(POINT p1, POINT p2, POINT p3) // 1:右
{
    if((ll)(p1.x - p3.x) * (p2.y - p3.y) < (ll)(p2.x - p3.x) * (p1.y - p3.y))
        return 1;
    return 0;
}

bool OK(ROBOT r, LINE a)
{
    if(a.s.x < 0 || a.s.y < 0 || a.e.x < 0 || a.e.y < 0)
        return true;
    int min_x = min(a.s.x, a.e.x);
    int max_x = max(a.s.x, a.e.x);
    int min_y = min(a.s.y, a.e.y);
    int max_y = max(a.s.y, a.e.y);
    if(a.s.x == a.e.x)
        if((a.s.x <= r.x1 && a.s.x <= r.x2) || (a.s.x >= r.x1 && a.s.x >= r.x2) || max_y <= r.y1 || min_y >= r.y2)
            return false;
    if(a.s.y == a.e.y)
        if((a.s.y <= r.y1 && a.s.y <= r.y2) || (a.s.y >= r.y1 && a.s.y >= r.y2) || max_x <= r.x1 || min_x >= r.x2)
            return false;
    return true;
}

int main()
{
    int T;
    while(scanf("%d", &T) != EOF)
    {
        while(T --)
        {   
            bool flag = true;
            scanf("%d %d", &n, &m);
            for(int i = 1; i <= n; i++)
                scanf("%d %d", &p[i].x, &p[i].y);
            p[n + 1] = p[1];
            p[n + 2] = p[2];
            for(int i = 1; i <= n && flag; i++)
            {
                l[i].s = p[i];
                l[i].e = p[i + 1];
            }
            for(int i = 1; i <= n; i++)
                dir[i] = Dir(l[i].s, l[i].e, p[i + 2]);
            for(int i = 1; i <= n && flag; i++)
            {   
                ROBOT a;
                a.x1 = a.x2 = l[i].e.x;
                a.y1 = a.y2 = l[i].e.y;
                int dx = l[i].e.x - l[i].s.x;
                int dy = l[i].e.y - l[i].s.y;
                if(dir[i] == 1) //内角向右
                {
                    if(dx > 0)
                    {
                        a.x1 -= m;
                        a.y1 -= m; 
                    }
                    if(dx < 0)
                    {
                        a.x2 += m;
                        a.y2 += m;
                    }
                    if(dy > 0)
                    {
                        a.x2 += m;
                        a.y1 -= m;   
                    }
                    if(dy < 0)
                    {   
                        a.x1 -= m;
                        a.y2 += m;
                    }
                }
                else
                {
                    if(dx > 0)  //外角向左
                    {
                        a.x2 += m;
                        a.y1 -= m; 
                    }
                    if(dx < 0)
                    {
                        a.x1 -= m;
                        a.y2 += m;
                    }
                    if(dy > 0)
                    {
                        a.x2 += m;
                        a.y2 += m;
                    }
                    if(dy < 0)
                    {   
                        a.x1 -= m;
                        a.y1 -= m;
                    }
                }
                for(int i = 1; i <= n && flag; i++)
                    if(OK(a, l[i])) //true表示有交叉
                        flag = false;   
            }
            printf("%s\n", flag ? "Yes" : "No");
        }
    }
}


  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
《后端 offer 收割机养成指南》是一本有关后端技术与求职的指南,主要面向想要成为后端工程师的人群。这份PDF提供了一些实用的技术知识和求职建议,有助于读者了解后端技术的要点和掌握核心技能。 首先,这本指南详细介绍了后端工程师的职责和岗位要求。后端工程师主要负责构建和维护服务器端的数据处理逻辑和业务逻辑。他们需要具备扎实的编程基础,熟悉常用的后端开发语言和框架,如Java、Python、Node.js等,并能够熟练使用数据库。 指南中还介绍了一些后端工程师常用的技术栈和工具,如RESTful API、微服务架构、消息队列等。这些技术和工具是现代后端开发中不可或缺的组成部分,掌握它们将有助于提升后端工程师的工作效率和开发质量。 此外,这本指南还分享了一些求职的经验和建议。它提供了寻找后端工程师职位的途径和方法,并给出了一些面试准备和面试技巧。通过学习这些经验和建议,读者可以更好地应对后端工程师的面试挑战,并提升自己的求职竞争力。 总而言之,《后端 offer 收割机养成指南》是一本对于想要成为后端工程师的人们非常有价值的指南。它不仅提供了掌握后端技术的核心知识和技能,还分享了求职方面的经验和建议。希望这本指南对读者在后端领域的学习和求职之路上有所帮助。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值