[Wannafly挑战赛14 C 可达性]强连通分量

[Wannafly挑战赛14 C 可达性]强连通分量

分类:Data Structure Strongly Connected Components

1. 题目链接

[Wannafly挑战赛14 C 可达性]

2. 题意描述

给出一个 0 N 10 5 点数、 0 M 10 5 边数的有向图,
输出一个尽可能小的点集,使得从这些点出发能够到达任意一点,如果有多个这样的集合,输出这些集合升序排序后字典序最小的。
输入描述:
第一行为两个整数 1 n , m 10 5
接下来 M 行,每行两个整数 1 u , v n 表示从点 u 至点 v 有一条有向边。
数据保证没有重边、自环。
输出描述:
第一行输出一个整数 z,表示作为答案的点集的大小;
第二行输出 z 个整数,升序排序,表示作为答案的点集。

输入

7 10
4 5
5 1
2 5
6 5
7 2
4 2
1 2
5 3
3 5
3 6
输出
2
4 7

3. 解题思路

对有向图强连通缩点之后,可以得到多个DAG。
那么,对于每一个DAG,取出所有入度为0的强连通分量,然后求这些连通分量中编号最小的顶点即可。

4. 实现代码

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;

const int inf = 0x3f3f3f3f;
const ll infl = 0x3f3f3f3f3f3f3f3fLL;
template<typename T> inline void umax(T &a, T b) { a = max(a, b); }
template<typename T> inline void umin(T &a, T b) { a = min(a, b); }
void debug() { cout << endl; }
template<typename T, typename ...R> void debug (T f, R ...r) { cout << "[" << f << "]"; debug (r...); }

const int MAXN = 100010;
const int MAXM = 100010;
struct Edge {
    int v, next;
} edge[MAXM];
int head[MAXN], tot;
int Low[MAXN], DFN[MAXN], Stack[MAXN], Belong[MAXN]; //Belong 数组的值是 1~scc
int Index, top;
int scc;//强连通分量的个数
bool Instack[MAXN];
int num[MAXN];//各个强连通分量包含点的个数,数组编号 1~scc
void add_edge(int u, int v) {
    edge[tot].v = v; edge[tot].next = head[u]; head[u] = tot++;
}
void Tarjan(int u) {
    int v;
    Low[u] = DFN[u] = ++Index;
    Stack[top++] = u;
    Instack[u] = true;
    for (int i = head[u]; i != -1; i = edge[i].next) {
        v = edge[i].v;
        if (!DFN[v]) {
            Tarjan(v);
            if ( Low[u] > Low[v] )Low[u] = Low[v];
        }
        else if (Instack[v] && Low[u] > DFN[v])
            Low[u] = DFN[v];
    }
    if (Low[u] == DFN[u]) {
        scc++;
        do {
            v = Stack[--top];
            Instack[v] = false;
            Belong[v] = scc;
            num[scc]++;
        }
        while ( v != u);
    }
}

bool flag[MAXN];

void init() {
    tot = 0;
    memset(head, -1, sizeof(head));
    memset(flag, false, sizeof(flag));
}

int n, m;

int main() {
#ifdef ___LOCAL_WONZY___
    freopen("input.txt", "r", stdin);
#endif // ___LOCAL_WONZY___
    while (~scanf("%d %d", &n, &m)) {
        init();
        int u, v;
        for (int i = 1; i <= m; ++i) {
            scanf("%d %d", &u, &v);
            add_edge(u, v);
        }
        memset(DFN, 0, sizeof(DFN));
        memset(Instack, false, sizeof(Instack));
        memset(num, 0, sizeof(num));
        Index = scc = top = 0;
        for (int i = 1; i <= n; i++) {
            if (!DFN[i]) Tarjan(i);
        }

        for (int u = 1; u <= n; ++u) {
            for (int i = head[u]; i != -1; i = edge[i].next) {
                v = edge[i].v;
                if (Belong[u] == Belong[v]) continue;
                flag[Belong[v]] = true;
            }
        }
        std::vector<int> ans;
        for (int i = 1; i <= n; ++i) {
            if (flag[Belong[i]] == true) continue;
            ans.push_back(i);
            flag[Belong[i]] = true;
        }
        printf("%d\n", ans.size());
        for (int i = 0; i < ans.size(); ++i) {
            if (i != 0) printf(" ");
            printf("%d", ans[i]);
        }
        printf("\n");
    }
#ifdef ___LOCAL_WONZY___
    cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << "ms." << endl;
#endif // ___LOCAL_WONZY___
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ACMore_Xiong/article/details/80025020