4309 消灭老鼠(哈希表存储一个向量表示一条直线)

1. 问题描述:

约翰的农场可以看作一个二维平面。农场中有 n 个老鼠,在毁坏着农田。第 i 个老鼠的位置坐标为 (xi,yi)。不同老鼠可能位于同一位置。在 (x0,y0) 处,装有一个双向发射的激光枪,该位置没有老鼠。激光枪每次发射都可以将穿过点 (x0,y0) 的某一条直线上的所有老鼠都消灭掉。请问,为了消灭所有老鼠,至少需要激光枪发射几次。

输入格式

第一行包含三个整数 n,x0,y0,表示共有 n 只老鼠,激光枪的位置为 (x0,y0)。接下来 n 行,每行包含两个整数 xi,yi,表示第 i 只老鼠的位置为 (xi,yi)。

输出格式

一个整数,表示激光枪的最少发射次数。

数据范围

前 5 个测试点满足 1 ≤ n ≤ 5。
所有测试点满足 1 ≤ n ≤ 1000,−10 ^ 4 ≤ xi,yi ≤ 10 ^ 4。

输入样例1:

4 0 0
1 1
2 2
2 0
-1 -1

输出样例1:

2

输入样例2:

2 1 2
1 1
1 0

输出样例2:

1
来源:https://www.acwing.com/problem/content/4312/

2. 思路分析:

分析题目可以知道实际上我们需要求解的是所有点与源点(x0,y0)构成的直线的数目,所以我们需要根据点与点的坐标计算出直线的斜率这样两个点就可以确定一条直线,所以问题就转化为了如何对直线进行判重?也即判断他们是否是重合的,一般有两种方法:① 计算斜率k和截距b,k和b相同那么所有点都在这条直线上;② 存储一个向量(x - x0, y - y0)用来标识一条直线;由于第一种方法计算斜率k的时候有可能会产生精度问题,而第二种方法存储的其实是一个向量那么是没有精度问题的,一般采取第二种方法来存储,这样可以标识一条直线,并且这个向量应该是最简的,也即x - x0和 y - y0的最大公约数为1,这样就可以唯一标识直线的方向,由于向量是有方向的,所以我们固定x - x0是正的这样相对方向就确定了,使用哈希表记录所有标识直线的向量即可,最终哈希表的大小就是直线的条数。

3. 代码如下:

class Solution:
    # 求解a, b的最大公约数
    def gcd(self, a: int, b: int):
        return a if b == 0 else self.gcd(b, a % b)

    def process(self):
        n, x0, y0 = map(int, input().split())
        mp = dict()
        for i in range(n):
            x, y = map(int, input().split())
            x -= x0
            y -= y0
            # 求解x和y的最大公约数最终x, y才是最简的
            g = self.gcd(x, y)
            # (x, y)表示一个向量
            x //= g
            y //= g
            if x < 0:
                # 将第一个数字变为正数这样相对方向就固定了, 例如(1, 1)和(-1, -1)标识的其实是一条直线
                x = -x
                y = -y
            mp[(x, y)] = 1
        return len(mp)


if __name__ == '__main__':
    print(Solution().process())
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值