给出一个有向图,求一个最大的结点集合,任意两个点u,v。u可到达v或v可到达u。
一个强连通分量肯定一起选的。而且只能在一条路径上。
所以先找出所有scc,然后缩点找一条最大权的路径,按拓扑序跑DAG上的dp。
注意0,0这组数据
#include<bits/stdc++.h> using namespace std; const int maxn = 1005,maxm = 5e5+1; int head[maxn],to[maxm],nxt[maxm]; void addEdge(int u,int v,int i) { to[i] = v; nxt[i] = head[u]; head[u] = i; } int pre[maxn],low[maxn],sccno[maxn],dfs_clock,scc_cnt; stack<int> stk; void tarjan(int u) { pre[u] = low[u] = ++dfs_clock; stk.push(u); for(int i = head[u]; ~i; i = nxt[i]){ int v = to[i]; if(!pre[v]){ tarjan(v); low[u] = min(low[u],low[v]); }else if(!sccno[v]){ low[u] = min(low[u],pre[v]); } } if(pre[u] == low[u]){ scc_cnt++; while(stk.size()){ int x = stk.top(); stk.pop(); sccno[x] = scc_cnt; if(x == u) break; } } } void find_scc(int n) { memset(pre,0,sizeof(pre)); memset(sccno,0,sizeof(sccno)); dfs_clock = scc_cnt = 0; for(int i = 0; i < n; i++){ if(!pre[i]) tarjan(i); } } vector<int> G[maxn]; int wei[maxn], deg[maxn]; void buildDAG(int n) { for(int i = 1; i <= scc_cnt; i++) G[i].clear(),deg[i] = wei[i] = 0; for(int u = 0; u < n; u++){ int v0 = sccno[u]; wei[v0]++; for(int i = head[u]; ~i; i = nxt[i]){ int v1 = sccno[to[i]]; if(v0 != v1) G[v0].push_back(v1),deg[v1]++; } } } int dp[maxn]; int topo() { memset(dp,-1,sizeof(dp)); queue<int> q; for(int i = 1; i <= scc_cnt; i++){ if(!deg[i]) q.push(i),dp[i] = wei[i]; } while(q.size()){ int u = q.front(); q.pop(); for(int i = 0; i < (int)G[u].size(); i++){ int v = G[u][i]; dp[v] = max(dp[v],dp[u]+wei[v]); if(--deg[v] == 0) q.push(v); } } int ans = 0; for(int i = 1; i <= scc_cnt; i++){ ans = max(dp[i],ans); } return ans; } int main() { //freopen("in.txt","r",stdin); int T; scanf("%d",&T); while(T--){ int n,m; memset(head,-1,sizeof(head)); scanf("%d%d",&n,&m); for(int i = 0; i < m; i++){ int u,v; scanf("%d%d",&u,&v); addEdge(u-1,v-1,i); } find_scc(n); buildDAG(n); printf("%d ",topo()); } return 0; }