【題解】TIOJ 1683 . 最大集團 The Largest Clique

【範例】Tarjan algorithm
【題目敘述】https://tioj.ck.tp.edu.tw/problems/1683
【解題想法】Tarjan algorithm + Topological sort (拓撲排序)

  • Tarjan algorithm:收縮所有的SCC (Strongly Connected Component, 強連通分量),變成一張DAG (Directed Acyclic Graph, 有向無環圖)
  • Topological sort (拓撲排序):求最長路徑
#include <bits/stdc++.h>
using namespace std;
int t, n, m, a, b, instk[10005], dfn[10005], low[10005], idx;
int fa[10005], scc_sz[10005], in[10005], dp[10005], scc_cnt, mx;
vector <int> g[10005], g2[10005];
stack <int> stk;

void tarjan(int x){
    instk[x] = 1;
    stk.push(x);
    dfn[x] = low[x] = ++idx;
    for (int i:g[x]){
        if (!dfn[i]){
            tarjan(i);
            low[x] = min(low[x], low[i]);
        }
        else if (instk[i]) low[x] = min(low[x], dfn[i]);
    }
    if (low[x] == dfn[x]){
        scc_cnt++;
        while (1){
            int now = stk.top();
            stk.pop();
            fa[now] = scc_cnt;
            scc_sz[scc_cnt]++;
            instk[now] = 0;
            if (now == x) break;
        }
    }
}

int main(){
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    cin >> t;
    while (t--){
        cin >> n >> m;
        scc_cnt = 0;
        idx = 0;
        mx = 0;
        for (int i = 1; i <= n; i++){
            g[i].clear();
            g2[i].clear();
            dfn[i] = 0;
            low[i] = 0;
            fa[i] = 0;
            scc_sz[i] = 0;
            in[i] = 0;
            dp[i] = 0;
        }
        for (int i = 0; i < m; i++){
            cin >> a >> b;
            g[a].push_back(b);
        }
        for (int i = 1; i <= n; i++){
            if (!dfn[i]) tarjan(i);
        }
        for (int i = 1; i <= n; i++){
            for (int j:g[i]){
                if (fa[i] != fa[j]){
                    g2[fa[i]].push_back(fa[j]);
                    in[fa[j]]++;
                }
            }
        }
        queue <int> q;
        for (int i = 1; i <= scc_cnt; i++){
            //cout << i << " " << scc_sz[i] << " " << in[i] << "\n";
            if (in[i] == 0) q.push(i);
        }
        while (!q.empty()){
            int now = q.front();
            q.pop();
            dp[now] += scc_sz[now];
            //cout << now << " " << dp[now] << "\n";
            mx = max(mx, dp[now]);
            for (int i:g2[now]){
                dp[i] = max(dp[i], dp[now]);
                in[i]--;
                if (in[i] == 0) q.push(i);
            }
        }
        cout << mx << "\n";
    }
}
分享本文 Share with friends