【算法训练营】凸包,图(Python实现)

凸包


描述

给定n个二维平面上的点,求他们的凸包。

输入

第一行包含一个正整数n。

接下来n行,每行包含两个整数x,y,表示一个点的坐标。

输出

令所有在凸包极边上的点依次为p1,p2,...,pm(序号),其中m表示点的个数,请输出以下整数:

(p1 × p2 × ... × pm × m) mod (n + 1)

样例1输入

10
7 9
-8 -1
-3 -1
1 4
-3 9
6 -4
7 5
6 6
-6 10
0 8

样例1输出

7

样例1解释

所以答案为(9 × 2 × 6 × 7 × 1 × 5) % (10 + 1) = 7

样例2

请查看下发文件内的sample2_input.txt和sample2_output.txt。

限制

3 ≤ n ≤ 10^5

所有点的坐标均为范围(-10^5, 10^5)内的整数,且没有重合点。每个点在(-10^5, 10^5) × (-10^5, 10^5)范围内均匀随机选取

极边上的所有点均被视作极点,故在输出时亦不得遗漏

时间:4 sec

空间:512 MB

代码实现

python 复制代码
from typing import List, Tuple

class Ip:
    def __init__(self, x:int = 0, y:int = 0, i:int = 0) -> None:
        self.x = x
        self.y = y
        self.i = i

    def __sub__(self, other: 'Ip') -> 'Ip':
        return Ip(self.x - other.x, self.y - other.y)

    @classmethod
    def read(cls, index: int) -> 'Ip':
        x, y = map(int, input().strip().split())
        return cls(x, y, index)

def cross_product(a: Ip, b: Ip) -> int:
    return a.x * b.y - a.y * b.x

def convex(a: List[Ip]) -> List[Ip]:
    a.sort(key=lambda p: (p.x, p.y))
    b = []
    for p in a:
        while len(b) > 1:
            if cross_product(b[-1] - b[-2], p - b[-2]) <= 0:
                break
            b.pop()
        b.append(p)
    temp = b[:]
    for p in reversed(a[:-1]):
        while len(b) > len(temp):
            if cross_product(b[-1] - b[-2], p - b[-2]) <= 0:
                break
            b.pop()
        b.append(p)
    return b[:-1]

if __name__ == "__main__":
    n = int(input().strip())
    a = [Ip.read(i + 1) for i in range(n)]
    b = convex(a)
    ans = len(b)
    for p in b:
        ans = (ans * p.i) % (n + 1)
    print(ans)


描述

一个数列 a 称为合法的当且仅对于所有的位置 i, j(i < j ≤ n),都不存在一条从 aj 点连向 ai 的有向边。现在有很多个有向无环图,请你判断每个图是否只存在唯一的合法数列。
输入

输入的第一行包含一个正整数 T ,表示数据组数。

对于每组数据,第一行包含两个正整数 n, m,表示图的节点个数和边数。

接下来 m 行,每行包含两个正整数 x, y(x, y ≤ n),表示这个图有一条从 x 到 y 的有向边。

保证没有自环和重边。
输出

输出 T 行,若所给的图存在唯一的合法数列,输出 1,否则输出 0。
样例1输入

复制代码
`2
3 2
1 2
2 3
3 2
1 2
1 3
`

样例1输出

复制代码
`1
0
`

样例1解释

第一个图只有一个合法数列:1、2、3;

第二个图有两个合法数列:1、2、3 或者 1、3、2。
样例2

请查看下发文件内的sample2_input.txt和sample2_output.txt。

限制

对于50%的数据,n, m ≤ 100;

对于100%的数据,T ≤ 100, n, m ≤ 10000。

时间:4 sec

空间:512 MB

提示

[本题就是判断一个有向无环图是否存在唯一的拓扑序列。]

[回忆一下求拓扑序列是如何做的:每一次都取一个入度为0的点,将这个点取出来放进拓扑序列里,然后将这个点连向的所有点的入度减去1。]

[可以发现,在"每一次都取一个入度为0"这一步,若入度为0的点数多于1个,则显然拓扑序不唯一。]

[因此按照这个拓扑序算法做一遍就好。]

代码实现

python 复制代码
from collections import deque


def has_unique_topological_order(n, m, edges):
    in_degrees = [0] * (n + 1)
    adj_list = [[] for _ in range(n + 1)]

    for x, y in edges:
        in_degrees[y] += 1
        adj_list[x].append(y)

    zero_degree_queue = deque()

    for i in range(1, n + 1):
        if in_degrees[i] == 0:
            zero_degree_queue.append(i)

    count = 0
    while zero_degree_queue:
        if len(zero_degree_queue) > 1:
            return 0

        node = zero_degree_queue.popleft()
        count += 1

        for neighbor in adj_list[node]:
            in_degrees[neighbor] -= 1
            if in_degrees[neighbor] == 0:
                zero_degree_queue.append(neighbor)

    return 1 if count == n else 0


def main():
    T = int(input())
    for _ in range(T):
        n, m = map(int, input().split())
        edges = [tuple(map(int, input().split())) for _ in range(m)]
        print(has_unique_topological_order(n, m, edges))


if __name__ == "__main__":
    main()
相关推荐
Funny_AI_LAB8 分钟前
MetaAI最新开源Llama3.2亮点及使用指南
算法·计算机视觉·语言模型·llama·facebook
NuyoahC15 分钟前
算法笔记(十一)——优先级队列(堆)
c++·笔记·算法·优先级队列
jk_10117 分钟前
MATLAB中decomposition函数用法
开发语言·算法·matlab
penguin_bark1 小时前
69. x 的平方根
算法
一休哥助手1 小时前
Redis 五种数据类型及底层数据结构详解
数据结构·数据库·redis
这可就有点麻烦了1 小时前
强化学习笔记之【TD3算法】
linux·笔记·算法·机器学习
苏宸啊1 小时前
顺序表及其代码实现
数据结构·算法
lin zaixi()1 小时前
贪心思想之——最大子段和问题
数据结构·算法
FindYou.1 小时前
C - Separated Lunch
算法·深度优先
夜雨翦春韭1 小时前
【代码随想录Day30】贪心算法Part04
java·数据结构·算法·leetcode·贪心算法