【题目链接】
题意:有向图最大团,即选出一些点,使得任意两点u, v,要么u可以到v,要么v可以到u,也可以互达。
先SCC缩点变为DAG,然后求最长路。
/* Pigonometry */ #include <cstdio> #include <algorithm> using namespace std; const int maxn = 1005, maxm = 50005, maxs = 10000, maxq = 10000; int n, m, head[maxn], cnt, head2[maxn], cnt2, dp[maxn], tot, belong[maxn], size[maxn], dfn[maxn], low[maxn], clo, q[maxq], du[maxn]; bool ins[maxn]; struct _edge { int v, next; } g[maxm << 1], g2[maxm << 1]; inline int iread() { int f = 1, x = 0; char ch = getchar(); for(; ch < '0' || ch > '9'; ch = getchar()) f = ch == '-' ? -1 : 1; for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0'; return f * x; } inline void add(int u, int v) { g[cnt] = (_edge){v, head[u]}; head[u] = cnt++; } inline void add2(int u, int v) { g2[cnt2] = (_edge){v, head2[u]}; head2[u] = cnt2++; } int sta[maxs], top; inline void tarjan(int x) { dfn[x] = low[x] = ++clo; ins[sta[++top] = x] = 1; for(int i = head[x]; ~i; i = g[i].next) if(!dfn[g[i].v]) tarjan(g[i].v), low[x] = min(low[x], low[g[i].v]); else if(ins[g[i].v]) low[x] = min(low[x], dfn[g[i].v]); if(dfn[x] == low[x]) { size[++tot] = 0; while(1) { int u = sta[top--]; belong[u] = tot; ins[u] = 0; size[tot]++; if(u == x) break; } } } int main() { int T = iread(); while(T--) { n = iread(); m = iread(); for(int i = 1; i <= n; i++) head[i] = head2[i] = -1, ins[i] = dp[i] = du[i] = dfn[i] = low[i] = 0; cnt = cnt2 = clo = tot = 0; for(int i = 1; i <= m; i++) { int u = iread(), v = iread(); add(u, v); } top = 0; 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 = g[j].next) if(belong[i] != belong[g[j].v]) { add2(belong[i], belong[g[j].v]); du[belong[g[j].v]]++; } int h = 0, t = 0, ans = 0; for(int i = 1; i <= tot; i++) if(!du[i]) dp[q[t++] = i] = size[i], ins[i] = 1; while(h != t) { int u = q[h++]; ans = max(ans, dp[u]); for(int i = head2[u]; ~i; i = g2[i].next) { dp[g2[i].v] = max(dp[g2[i].v], dp[u] + size[g2[i].v]); if(!ins[g2[i].v]) q[t++] = g2[i].v; } ins[u] = 0; } printf("%d\n", ans); } return 0; }