POJ 2762 Tarjan SCC

题意

传送门 POJ 2762 Going from u to v or from v to u?

题解

判断有向图中任意两点间是否都存在至少一条路径。

T a r j a n Tarjan Tarjan 求解 S C C SCC SCC,缩点建立新图,得到一个 D A G DAG DAG。对于同一个 S C C SCC SCC 内的两个点,满足条件。问题转化为判断 D A G DAG DAG 上任意两点间是否存在至少一条路径。可以观察到,当 D A G DAG DAG 中某个节点入度或出度大于 1 1 1,则必然存在不满足条件的两个节点;满足条件的 D A G DAG DAG 应该是链状的图。除此之外,还要保证图的连通性,属于不同链状的 D A G DAG DAG 的两个节点显然不满足条件;那么只要判断图中入度为 0 0 0 的节点是否为 1 1 1 即可。总时间复杂度 O ( N + M ) O(N+M) O(N+M)

#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 1005, maxm = 6005;
int T, N, M, num, scc, low[maxn], dfn[maxn], sc[maxn];
int tot, head[maxn], to[maxm], nxt[maxm];
int top, st[maxn], in[maxn], out[maxn];
bool ins[maxn];

void init()
{
    
    
    num = tot = top = scc = 0;
    memset(dfn, 0, sizeof(dfn)), memset(head, 0, sizeof(head));
    memset(ins, 0, sizeof(ins));
    memset(in, 0, sizeof(in)), memset(out, 0, sizeof(out));
}

inline void add(int x, int y) {
    
     to[++tot] = y, nxt[tot] = head[x], head[x] = tot; }

void tarjan(int x)
{
    
    
    low[x] = dfn[x] = ++num;
    st[++top] = x, ins[x] = 1;
    for (int i = head[x]; i; i = nxt[i])
    {
    
    
        int y = to[i];
        if (!dfn[y])
            tarjan(y), low[x] = min(low[x], low[y]);
        else if (ins[y])
            low[x] = min(low[x], dfn[y]);
    }
    if (dfn[x] == low[x])
    {
    
    
        ++scc;
        int y;
        do
        {
    
    
            y = st[top--], ins[y] = 0, sc[y] = scc;
        } while (y != x);
    }
}

int main()
{
    
    
    scanf("%d", &T);
    while (T--)
    {
    
    
        init();
        scanf("%d%d", &N, &M);
        for (int i = 1, x, y; i <= M; ++i)
            scanf("%d%d", &x, &y), add(x, y);
        for (int i = 1; i <= N; ++i)
            if (!dfn[i])
                tarjan(i);
        for (int i = 1; i <= N; ++i)
            for (int j = head[i]; j; j = nxt[j])
            {
    
    
                int x = sc[i], y = sc[to[j]];
                if (x != y)
                    ++out[x], ++in[y];
            }
        int a = 0, b = 0;
        for (int i = 1; i <= scc; ++i)
            a += in[i] > 1 || out[i] > 1, b += !in[i];
        puts((!a && b == 1) ? "Yes" : "No");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/neweryyy/article/details/115033181