📜  门|门 CS 1996 |第 36 题(1)

📅  最后修改于: 2023-12-03 15:42:20.670000             🧑  作者: Mango

题目

门|门CS 1996 | 第36题

题目描述

给定 $n$ $(1<=n<=50)$ 个人,他们之间可能会存在矛盾,现在有若干辆车将这些人运走。要求运走的车数最少,同时保证每辆车中任意两个人之间都没有矛盾。

输入格式

第一行:整数 $n$,表示人数。

接下来 $n$ 行,每行一个字符串 $s$,表示当前人和其他人是否存在矛盾的情况,其中 $s$ 的第 $i$ 个字符为 'Y' 表示当前人和第 $i$ 个人存在矛盾,为 'N' 表示不存在矛盾。

输出格式

一行一个整数,表示运走的车数最少。

样例输入
5
NYNNN
YNYNN
NYNYN
NNYNY
NNNYN
样例输出
3
解题思路

这道题可以使用贪心算法来解决。

我们可以将没有矛盾的人看做是一个个集合,而有矛盾的人看做是不同的集合,然后对集合进行合并,直到所有的人都在同一个集合中。

对于两个集合之间的合并,我们可以按照他们的大小进行合并,这样能够使得合并后的集合尽可能的小,从而运输的次数尽可能的少。

实现上,我们可以使用并查集来维护集合之间的关系,并记录每个集合的大小,然后按照大小进行合并即可。

设 $n$ 为人数,时间复杂度 $O(n^2 logn)$。

参考代码
class UnionFind:
    def __init__(self, n: int):
        self.parent = [i for i in range(n)]
        self.size = [1 for _ in range(n)]
        self.count = n
    
    def find(self, p: int) -> int:
        while p != self.parent[p]:
            self.parent[p] = self.parent[self.parent[p]]
            p = self.parent[p]
        return p
    
    def union(self, p: int, q: int):
        root_p, root_q = self.find(p), self.find(q)
        if root_p == root_q:
            return
        if self.size[root_p] < self.size[root_q]:
            self.parent[root_p] = root_q
            self.size[root_q] += self.size[root_p]
        else:
            self.parent[root_q] = root_p
            self.size[root_p] += self.size[root_q]
        self.count -= 1
    
    def get_count(self) -> int:
        return self.count

def min_cars(n: int, conflicts: List[str]) -> int:
    uf = UnionFind(n)
    for i in range(n):
        for j in range(i + 1, n):
            if conflicts[i][j] == 'N':
                uf.union(i, j)
    return uf.get_count()

n = int(input())
conflicts = [input() for _ in range(n)]
print(min_cars(n, conflicts))
参考资料
  • 《算法竞赛进阶指南》