题目链接


题意:给出一张有向图,求一个结点数最大的结点集,使得该结点集中随意两个结点u和v满足:要么u能够到到v,要么v能够到达u(u和v能够互相到达)

思路:我们能够缩点,用Tarjan求出全部强连通分量,让每一个SCC的权值等于它的结点个数。因为SCC图是有一个DAG,使用DP求解。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <stack>
#include <algorithm>

using namespace std;

const int MAXN = 1005;

vector<int> g[MAXN], scc[MAXN], G[MAXN];
stack<int> s;
int pre[MAXN], lowlink[MAXN], sccno[MAXN], sccnum[MAXN], dfs_clock, scc_cnt; 
int d[MAXN];
int n, m;

int Tarjan(int u) {
    lowlink[u] = pre[u] = ++dfs_clock;
    s.push(u);
    for (int i = 0; i < g[u].size(); i++) {
        int v = g[u][i]; 
        if (!pre[v]) {
            Tarjan(v); 
            lowlink[u] = min(lowlink[v], lowlink[u]);
        } 
        else if (!sccno[v]) {
            lowlink[u] = min(lowlink[u], pre[v]); 
        }
    }
    if (lowlink[u] == pre[u]) {
        scc_cnt++;
        for (;;) {
            int x = s.top(); 
            s.pop();
            sccno[x] = scc_cnt;
            sccnum[sccno[x]]++;
            if (x == u) break;
        } 
    }
}

void find_scc() {
    memset(pre, 0, sizeof(pre));
    memset(lowlink, 0, sizeof(lowlink));
    memset(sccno, 0, sizeof(sccno));
    memset(sccnum, 0, sizeof(sccnum));
    dfs_clock = scc_cnt = 0;
    for (int i = 0; i < n; i++)
        if (!pre[i])
            Tarjan(i);
}

int dp(int i) {
    int& ans = d[i]; 
    if (ans > 0) return ans;
    ans = sccnum[i];
    for (int j = 0; j < G[i].size(); j++) {
        int v = G[i][j];
        ans = max(ans, dp(v) + sccnum[i]);
    }
    return ans;
}

int main() {
    int cas;
    scanf("%d", &cas);
    while (cas--) {
        scanf("%d%d", &n, &m);
        for (int i = 0; i < n; i++)
            g[i].clear();
        int u, v;
        for (int i = 0; i < m; i++) {
            scanf("%d%d", &u, &v); 
            u--;
            v--;
            g[u].push_back(v);
        }

        find_scc();

        memset(d, -1, sizeof(d));
        memset(G, 0, sizeof(G));
        for (int u = 0; u < n; u++) {
            for (int i = 0; i < g[u].size(); i++) {
                int v = g[u][i]; 
                if (sccno[u] != sccno[v]) 
                    G[sccno[u]].push_back(sccno[v]); 
            } 
        }        

        int ans = 0;
        for (int i = 1; i <= scc_cnt; i++) 
            ans = max(ans, dp(i));

        printf("%d\n", ans);
    }
    return 0;
}