给出一个有 n 个顶点和 m 条边的无向连通图 G,没有重边和自环。

顶点的编号为 1∼n,边的编号为 1∼m,第 i 条边连接顶点 ui​ 和 vi​。

给出图上三个不同的顶点 A,B,C。判断是否有从点 A 经过点 B 到点 C 的简单路径。

简单路径指路径上的点互不相同,即不重复经过同一个点。

注意本题有多组测试数据(最多不超过10组),最后以0 0结束。

输入格式:

第一行有两个整数 n,m。 第二行有三个整数 A,B,C。 接下来 mm 行,每行两个整数 u_i 和 v_i。

输出格式:

对于每一组测试数据输出一行 YesNo

限制:

  • 3≤n≤2×1e5
  • n−1≤m≤min⁡(n(n−1)/2,2×1e5)
  • 1≤A,B,C≤n
  • 1≤ui<vi≤n

修改代码,不用vector开数组,但用它建图

// 简单路径
#include <cstdio>
#include <vector>
#include <stack>

using namespace std;

const int N = 2e5 + 2047;
int n, m, sa, sb, sc, tot, cnt;
int dfn[N], low[N], f[N];
vector<int> a[N], na[N];
stack<int> st;
int s[N], top, tp;

int min(int x, int y) { return x < y ? x : y; }

void tarjan(int u) {
    dfn[u] = low[u] = ++tot;
    //st.push(u);
    s[++top] = u;

    for (int v : a[u]) {
        if (!dfn[v]) {
            tarjan(v);
            low[u] = min(low[u], low[v]);
            if (low[v] == dfn[u]) {
                na[++cnt].push_back(u);
                na[u].push_back(cnt);
                // do {
                //     if (!st.empty()) {
                //         top = st.top();
                //         st.pop();
                //         na[top].push_back(cnt);
                //         na[cnt].push_back(top);
                //    }
                //} while (top != v);
                while(s[top] != v) {
                    tp = s[top--];
                    na[cnt].push_back(tp); // 方点连接点双内节点
                    na[tp].push_back(cnt);
                }

                na[cnt].push_back(v);
                na[v].push_back(cnt);
                top--;
                // if (!st.empty()) st.pop();
            }
        } else low[u] = min(low[u], dfn[v]);
    }
}

void dfs(int u, int fa) {
    f[u] = fa;

    for (int v : na[u]) {
        if (v == fa) continue;
        dfs(v, u);
    }
}

bool check(int u) {
    while (u != sc) {
        if (u > n) {
            for (int v : na[u]) {
                if (v == sb) return 1;
            }
        }
        u = f[u];
    }

    return 0;
}

int main()
{
    while (scanf("%d %d", &n, &m)) {
        if (!n && !m) break;
        for (int i = 1; i <= cnt; i++) {
            a[i].clear();
            na[i].clear();
            f[i] = low[i] = dfn[i] = 0;
            if (!st.empty()) st.pop();
        }
        tot = 0;
        cnt = n;
        scanf("%d %d %d", &sa, &sb, &sc);
        for (int u, v; m--;) {
            scanf("%d %d", &u, &v);
            a[u].push_back(v);
            a[v].push_back(u);
        }
        
        for (int i = 1; i <= n; i++) {
            if (!dfn[i]) tarjan(i);
        }

        dfs(1, 0);
        bool flag = check(sa);
        if (flag) puts("Yes");
        else puts("No");
        
    }
    return 0;
}

1 条评论

  • @ 2025-9-6 9:34:09
    // 简单路径
    #include <cstdio>
    #include <vector>
    #include <stack>
    
    using namespace std;
    
    const int N = 2e5 + 2047;
    int n, m, sa, sb, sc, tot, cnt;
    int dfn[N], low[N], f[N];
    vector<int> a[N], na[N];
    int s[N], top, tp;
    
    int min(int x, int y) { return x < y ? x : y; }
    
    void tarjan(int u) {
        dfn[u] = low[u] = ++tot;
        s[++top] = u;
    
        for (int v : a[u]) {
            if (!dfn[v]) {
                tarjan(v);
                low[u] = min(low[u], low[v]);
                // ★ 改1:条件 >=,否则会漏点双
                if (low[v] >= dfn[u]) {
                    na[++cnt].push_back(u);
                    na[u].push_back(cnt);
                    // ★ 改2:先弹到 v,再单独处理 v
                    while (s[top] != v) {
                        tp = s[top--];
                        na[cnt].push_back(tp);
                        na[tp].push_back(cnt);
                    }
                    tp = s[top--];
                    na[cnt].push_back(tp);
                    na[tp].push_back(cnt);
                }
            } else {
                low[u] = min(low[u], dfn[v]);
            }
        }
    }
    
    void dfs(int u, int fa) {
        f[u] = fa;
        for (int v : na[u]) {
            if (v == fa) continue;
            dfs(v, u);
        }
    }
    
    bool check(int u) {
        while (u != sc && u != 0) {
            if (u > n) {
                for (int v : na[u]) {
                    if (v == sb) return 1;
                }
            }
            u = f[u];
        }
        if (u == sb) return 1; // ★ 改3:sc 本身是 B 的情况
        return 0;
    }
    
    int main()
    {
        while (scanf("%d %d", &n, &m)) {
            if (!n && !m) break;
            // ★ 改4:清理范围到 cnt,重置变量
            for (int i = 1; i <= cnt; i++) {
                a[i].clear();
                na[i].clear();
                f[i] = low[i] = dfn[i] = 0;
            }
            tot = top = 0;
            cnt = n;
    
            scanf("%d %d %d", &sa, &sb, &sc);
            for (int u, v; m--;) {
                scanf("%d %d", &u, &v);
                a[u].push_back(v);
                a[v].push_back(u);
            }
            
            for (int i = 1; i <= n; i++) {
                if (!dfn[i]) tarjan(i);
            }
    
            // ★ 改5:DFS 从 sa 开始,保证父链能到 sc
            dfs(sa, 0);
            bool flag = check(sa);
            if (flag) puts("Yes");
            else puts("No");
        }
        return 0;
    }
    
    
    • 1