📜  门|门模拟 2017 |第 57 题(1)

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

「门|门模拟 2017」第 57 题 题解

这是一道使用 DFS 进行模拟的题目。

题目描述

题目传送门:「门|门模拟 2017」第 57 题

给出 $n$ 个正整数,表示由 $n$ 个门相连成的环。现在有 $m$ 次询问,每次询问给出三个整数 $a$、$b$、$c$,意思是从 $a$ 号门进入,一直顺时针走,走到第一个编号为 $b$ 的门时,如果这个门的状态为 $0$,那就全都变成 $1$,否则不变化,最后问走 $c$ 步之后停在哪一个门上。每次询问保证 $1 \leq a, b \leq n$,$a \neq b$,$1 \leq c \leq 10^9$。

算法分析

我们可以用一个 vector 存储每个门可以到达的下一个门的编号,然后用一个 bool 数组表示每个门的状态。

对于每一次询问,都可以将从 $a$ 号门开始可到达的所有门的状态进行改变。暴力模拟改变每个门的状态,然后依次走 $c$ 步即可。注意需要将 $c$ 取模 $n$,因为这 $n$ 个门是构成一个环的。

代码实现
// -*- coding: utf-8 -*-

#include<bits/stdc++.h>
#define rei register int
#define maxn 505000
#define pb push_back
using namespace std;

vector<int> t[maxn];
bool vis[maxn];

void dfs(int u) {
    for (rei i = 0; i < t[u].size(); ++i) {
        int v = t[u][i];
        if (!vis[v]) {
            vis[v] = 1;
            dfs(v);
        }
    }
}

int main() {
    // freopen("P4474.in", "r", stdin);
    // freopen("P4474.out", "w", stdout);
    ios::sync_with_stdio(false);

    int n, m, k;
    cin >> n >> m >> k;

    for (rei i = 1; i <= m; ++i) {
        int x, y;
        cin >> x >> y;
        t[x].pb(y);
        t[y].pb(x);
    }

    memset(vis, 0, sizeof vis);
    dfs(k);

    int pos = k;
    for (rei i = 1; i <= n; ++i) {
        if (vis[i] && i != k) {
            pos = i;
            break;
        }
    }

    int h = 0;
    for (rei i = 1, x, y; i <= n; ++i) {
        cin >> x >> y;
        int t = pos;
        for (rei j = 1; j <= y % n; ++j) {
            t = t == n ? 1 : t + 1;
            if (t == x) {
                if (!vis[x])
                    memset(vis, 0, sizeof vis);
                dfs(x);
                vis[x] = 1;
                vis[t] = !vis[t];
            }
        }
        cout << t << "\n";
    }
    return 0;
}

以上代码是 C++ 语言编写的。

复杂度分析

对于每次询问,我们都需要深度优先搜索,时间复杂度为 $O(n)$。对于每个门的状态的变化,最多需要改变 $n$ 个门的状态,所以时间复杂度为 $O(n^2)$。

总时间复杂度为 $O(n^3)$。但是由于题目给定了 $c$ 的范围,所以实际时间复杂度较小。