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

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

门|门 CS 1996 |第54题介绍

该题目可以帮助程序员加深对数据结构的理解,以及熟悉C++语言的基本操作和调试技巧。

题目说明

题目描述:给出n个门,每个门有一把钥匙,编号为1~n。有m个人,每个人有各自的一组钥匙,若有门的钥匙和他携带的钥匙相同,则可以打开该门。现在要求所有人都需要走进编号为1的门,求所有人必须要走过几扇门(包括1号门)。

输入格式:第一行输入n和m,接下来m行每行输入一个人所带的钥匙的个数以及对应的钥匙编号。 输出格式:输出所有人必须要走过的最小的门的数量。

解题思路

本题可以通过建立一个钥匙与门之间的映射关系,建立一个map或unorder_map, 将每个人所拥有的钥匙和对应的门的关系存储下来。

接下来依次遍历每个人所拥有的钥匙,将每个钥匙对应的门的编号标记为已开启状态,再对所有门进行广度优先遍历,寻找可达的门并进行标记。最终如果1号门被标记为已经开启,则所有人一定可以走到1号门。最后输出所有已经被标记过的门的数量即可。

代码示例
#include<iostream>
#include<map>
#include<queue>

using namespace std;

const int N = 1e5 + 10;

int n, m;
map<int, vector<int>> key_map;
queue<int> q;
int used[N];

int bfs() {
    int res = 0;
    q.push(1);
    used[1] = 1;

    while (q.size()) {
        int size = q.size();
        res++;

        while (size--) {
            int t = q.front();
            q.pop();

            if (key_map.count(t)) {
                for (auto door_id : key_map[t]) {
                    if (!used[door_id]) {
                        q.push(door_id);
                        used[door_id] = 1;
                    }
                }
                key_map.erase(t);
            }
        }
    }
    return res;
}

int main() {
    cin >> n >> m;

    while (m--) {
        int k;
        cin >> k;

        while (k--) {
            int x;
            cin >> x;
            key_map[x].push_back(n + m + 1);
        }
    }

    int res = bfs();

    cout << (used[1] ? res : -1);

    return 0;
}

代码中我们使用了C++标准库中的map,用来存储钥匙与门之间的映射关系,使得代码实现及其简便和易读。在搜索时,我们使用了BFS来搜索所有可达的门,用队列来管理搜索过程中未被扩展节点的状态,并用used数组来标记是否访问过相关节点。最终输出所有已经被标记过的门的数量即可。

返回的markdown格式如下:

# 门|门 CS 1996 |第54题介绍

该题目可以帮助程序员加深对数据结构的理解,以及熟悉C++语言的基本操作和调试技巧。

## 题目说明

题目描述:给出n个门,每个门有一把钥匙,编号为1~n。有m个人,每个人有各自的一组钥匙,若有门的钥匙和他携带的钥匙相同,则可以打开该门。现在要求所有人都需要走进编号为1的门,求所有人必须要走过几扇门(包括1号门)。

输入格式:第一行输入n和m,接下来m行每行输入一个人所带的钥匙的个数以及对应的钥匙编号。
输出格式:输出所有人必须要走过的最小的门的数量。

## 解题思路

本题可以通过建立一个钥匙与门之间的映射关系,建立一个map或unorder_map, 将每个人所拥有的钥匙和对应的门的关系存储下来。

接下来依次遍历每个人所拥有的钥匙,将每个钥匙对应的门的编号标记为已开启状态,再对所有门进行广度优先遍历,寻找可达的门并进行标记。最终如果1号门被标记为已经开启,则所有人一定可以走到1号门。最后输出所有已经被标记过的门的数量即可。

## 代码示例

```c++
#include<iostream>
#include<map>
#include<queue>

using namespace std;

const int N = 1e5 + 10;

int n, m;
map<int, vector<int>> key_map;
queue<int> q;
int used[N];

int bfs() {
    int res = 0;
    q.push(1);
    used[1] = 1;

    while (q.size()) {
        int size = q.size();
        res++;

        while (size--) {
            int t = q.front();
            q.pop();

            if (key_map.count(t)) {
                for (auto door_id : key_map[t]) {
                    if (!used[door_id]) {
                        q.push(door_id);
                        used[door_id] = 1;
                    }
                }
                key_map.erase(t);
            }
        }
    }
    return res;
}

int main() {
    cin >> n >> m;

    while (m--) {
        int k;
        cin >> k;

        while (k--) {
            int x;
            cin >> x;
            key_map[x].push_back(n + m + 1);
        }
    }

    int res = bfs();

    cout << (used[1] ? res : -1);

    return 0;
}

代码中我们使用了C++标准库中的map,用来存储钥匙与门之间的映射关系,使得代码实现及其简便和易读。在搜索时,我们使用了BFS来搜索所有可达的门,用队列来管理搜索过程中未被扩展节点的状态,并用used数组来标记是否访问过相关节点。最终输出所有已经被标记过的门的数量即可。