真正意义上由自己思维推断出的第一题。
实际上思路也和正解一致。
题意是给你一个有向图,让你求一个点集,使得点集中任意一对点对(u,v),要么u可以到v,要么v可以到u。
我们可以发现,对于一个SCC而言,要么都选,要么都不选(换句话说,如果我们选中了SCC中的任意一点,那么也可以顺便把SCC中的其他点也顺便选上)
这样我们先缩点,然后在新图上(每个点相当于一个SCC,并且点权为SCC的大小)跑DAG的最长路即可。
这个用一个dp实现。
设d[i]=以i为起点的最长路的长度。
则d[i] = max{d[j] + val[j] | G[i][j] != 0}
#include <cstdio> #include <cstring> #include <algorithm> #include <stack> using namespace std; const int maxn = 1005, maxm = 50005; stack<int> s; int t, n, m, tot, dfs_clock, scc_cnt; int h[maxn], dfn[maxn], low[maxn], sccno[maxn]; int h2[maxn], d[maxn], vis[maxn], val[maxn]; int tot2; struct edge { int v, next; }a[maxm], a2[maxm]; void add(int x, int y) { a[tot].v = y; a[tot].next = h[x]; h[x] = tot++; } void add2(int x, int y) { a2[tot2].v = y; a2[tot2].next = h2[x]; h2[x] = tot2++; } int dfs(int u, int fa) { s.push(u); int lowu = dfn[u] = ++dfs_clock; for (int i = h[u]; ~i; i = a[i].next) { int v = a[i].v; if (!dfn[v]) { int lowv = dfs(v, u); lowu = min(lowu, lowv); } else if (!sccno[v]) { lowu= min(lowu, dfn[v]); } } if (lowu == dfn[u]) { scc_cnt++; int scc_num = 0; for (;;) { scc_num++; int x = s.top(); s.pop(); sccno[x] = scc_cnt; if (x == u) break; } val[sccno[u]] = scc_num; } return low[u] = lowu; } int dp(int u) { if (vis[u]) return d[u]; vis[u] = 1; int& ans = d[u]; ans = val[u]; for (int i =h2[u]; ~i; i = a2[i].next) { int v = a2[i].v; ans = max(ans, dp(v) + val[u]); } return ans; } int main() { // freopen("uva11324.in","r",stdin); scanf("%d", &t); while (t--) { scanf("%d%d", &n, &m); memset(h, -1, sizeof h); tot = dfs_clock = scc_cnt = 0; memset(dfn, 0, sizeof dfn); memset(low, 0, sizeof low); memset(sccno, 0, sizeof sccno); memset(val, 0, sizeof val); for (int i = 1; i <= m; i++) { int x, y; scanf("%d%d", &x, &y); add(x, y); } for (int i = 1; i <= n; i++) if (!dfn[i]) dfs(i, 0); memset(h2, -1, sizeof h2); tot2 = 0; for (int u = 1; u <= n; u++) for (int i = h[u]; ~i; i = a[i].next) { int v = a[i].v; if (sccno[u] != sccno[v]) add2(sccno[u], sccno[v]); } int ans = 0; memset(vis, 0, sizeof vis); memset(d, 0, sizeof d); for (int i = 1; i <= n; i++) ans = max(ans, dp(sccno[i])); printf("%d ", ans); } return 0; }