首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> C++ 入門

ZOJ 3811 Untrusted Patrol 另解:純 DFS 遞歸標記

     編輯:C++ 入門

解法對比

本解法採用 遞歸 DFS 而非並查集,邏輯更直觀:

  1. 按信號順序依次從觸發器節點 DFS,只走「未訪問」且「無觸發器/已處理觸發器」的節點
  2. 遇到下一信號對應的觸發器節點即停止當前 DFS,標記可達
  3. 若某信號節點不可達 → No
  4. 最後再做一次全圖 DFS 檢查連通性

代碼實現

#include <iostream>
#include <cstring>
#include <vector>

const int MAXN = 110000;
int head[MAXN], vis[MAXN], sensor[MAXN];
struct Edge { int to, next; } edges[MAXN*4];
int ecnt;

void addEdge(int u, int v) {
    edges[ecnt] = {v, head[u]}; head[u] = ecnt++;
    edges[ecnt] = {u, head[v]}; head[v] = ecnt++;
}

void dfs(int u) {
    vis[u] = 1;
    for (int e = head[u]; ~e; e = edges[e].next) {
        int v = edges[e].to;
        if (vis[v]) continue;
        if (sensor[v]) { vis[v] = 1; continue; }  // 遇到未激活觸發器停止
        dfs(v);
    }
}

void dfsAll(int u, int& cnt) {
    vis[u] = 1; ++cnt;
    for (int e = head[u]; ~e; e = edges[e].next) {
        int v = edges[e].to;
        if (!vis[v]) dfsAll(v, cnt);
    }
}

int main() {
    int T; scanf("%d", &T);
    while (T--) {
        memset(head, -1, sizeof head);
        memset(vis, 0, sizeof vis);
        memset(sensor, 0, sizeof sensor);
        ecnt = 0;

        int n, m, k; scanf("%d%d%d", &n, &m, &k);
        for (int i=0, x; i

複雜度與優缺點

指標DFS 遞歸並查集 + BFS
時間O(n+m)O((n+m) α(n))
棧深度O(n) 風險棧溢出O(1) 額外空間
代碼簡潔度高中
適用場景n ≤ 10⁵, 深度可控通用、無棧溢出風險

注意事項

  • 遞歸 DFS 若圖深度大(如鏈圖)會棧溢出,建議改用顯式棧或並查集
  • sensor[v] 為 1 表示「尚未激活的觸發器」,DFS 遇到即標記訪問但不繼續深入
  • 全圖連通性檢查必須在所有信號處理完後進行,且需重置 vis[]
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved