📜  门| GATE-CS-2009 |问题 33(1)

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

门 | GATE-CS-2009 |问题 33

该问题是一个经典的计算机科学问题,涉及到图论和动态规划的知识。

问题描述

有 $n$ 扇门和 $m$ 把钥匙。每扇门都可以使用一些钥匙打开。给定每扇门可以使用的钥匙列表,问从起点开始,按任意顺序使用钥匙,是否能够到达终点。

输入格式

输入数据包含两行:

第一行为 $n\ (1 \leq n \leq 20)$,表示有 $n$ 扇门。

第二行包含 $n$ 个由空格隔开的字符串,每个字符串表示对应门能够使用的钥匙列表,每个列表中的钥匙用数字表示,不同钥匙之间用空格隔开,列表用中括号括起来。例如,"[1 2 3]" 表示有三把钥匙,编号分别为 1、2、3。

输出格式

如果可以到达终点,则输出 "Yes",否则输出 "No"。

示例

输入:

3
[1] [2] [3]

输出:

No
解题思路

可以使用动态规划解决,也可以使用深度优先搜索。

动态规划

使用 $dp_{i,j}$ 表示前 $i$ 个门能否使用钥匙 $j$ 到达终点,转移方程为:

$dp_{i,j}=\begin{cases}1, & i=0\text{ and }j=0 \dp_{i-1,j} \text{ or }dp_{i-1,k}, & \text{key }j \text{ can open }i^{th} \text{ gate, }k \text{ in the key list of }i^{th} \text{ gate}\end{cases}$

最终的答案为 $dp_{n,\text{end key}}$。

深度优先搜索

从起点开始进行深度优先搜索,搜索过程中记录已有钥匙的状态,并将搜索到的状态加入到已搜索状态集合中以避免重复搜索。当搜索到终点时返回结果,如果没有搜索到终点则返回 "No"。

代码实现
动态规划
keys = [] # 各门的钥匙列表
key_set = set() # 所有钥匙的集合

# 输入
n = int(input())
for keys_str in input().split():
    keys.append(set(map(int, keys_str[1:-1].split())))
    key_set |= keys[-1]

# dp 初始化
dp = [[False for _ in range(len(key_set))] for _ in range(n)]

# 边界条件
if 1 in keys[0]:
    dp[0][1] = True

# dp 转移
for i in range(1, n):
    for j in range(len(key_set)):
        if j in keys[i]:
            dp[i][j] = True
        else:
            for k in keys[i]:
                dp[i][j] |= dp[i-1][k]

# 输出
if dp[-1][len(key_set)-1]:
    print("Yes")
else:
    print("No")
深度优先搜索
def dfs(state: int, keys: List[set], visited: set):
    if state == len(keys) - 1:
        return True
    visited.add(state)
    for key in keys[state]:
        new_state = state
        for i, key_set in enumerate(keys):
            if i == state:
                continue
            if key in key_set and i not in visited:
                new_state |= 1 << i
        if new_state != state and dfs(new_state, keys, visited):
            return True
    return False

# 输入
n = int(input())
keys = []
for keys_str in input().split():
    keys.append(set(map(int, keys_str[1:-1].split())))

# 输出
if dfs(1, keys, set()):
    print("Yes")
else:
    print("No")