题意:
给你一张有向有环图。
问一笔画能走的最长长度是多少。
思路:
先用强连通缩点,得到DAG,再用拓扑排序求DAG最长路的思想得出答案。
注意缩点以后重新建图不能建自环鸭。
const int N = 1100+100; //点数
int n,m;
int scc, top, tot;
vector<int> G[N];
vector<int> E[N];
int low[N], dfn[N], belong[N],indeg[N],big[N],dp[N];
int stk[N], vis[N];
int ex[N][N];
void init(int n) {
for (int i = 0; i <= n; ++i) {
G[i].clear();
E[i].clear();
low[i] = 0;
dfn[i] = 0;
stk[i] = 0;
vis[i] = 0;
indeg[i]=0;
big[i]=0;
dp[i]=0;
}
scc = top = tot = 0;
}
void tarjan(int x) {
stk[top++] = x;
low[x] = dfn[x] = ++tot;
vis[x] = 1;
for (int to : G[x]) {
if (!dfn[to]) {
tarjan(to);
low[x] = min(low[x], low[to]);
} else if (vis[to]) {
low[x] = min(low[x], dfn[to]);
}
}
if (low[x] == dfn[x]) {
++scc;
int temp;
do {
temp = stk[--top];
belong[temp] = scc;
vis[temp] = 0;
} while (temp != x);
}
}
void toposort(){
queue<int> q;
fore(i,1,scc){
if(!indeg[i]) q.push(i);
}
while(!q.empty()){
int now=q.front();
q.pop();
for(int to:E[now]){
if(to==now) continue;
--indeg[to];
if(!indeg[to]) q.push(to);
uax(dp[to],dp[now]+big[to]);
}
}
}
signed main() {
int tc;
cin>>tc;
while(tc--){
cin>>n>>m;
init(n+5);
vector< pair<int,int> > rev;
for(int i=0; i<m; ++i){
int u,v;
cin>>u>>v;
rev.eb(mp(u,v));
G[u].eb(v);
}
for(int i=1; i<=n; ++i) if(!dfn[i]) tarjan(i);
for(int i=1; i<=n; ++i){
++big[belong[i]];
++dp[belong[i]];
}
for(int i=0; i<=scc; ++i) for(int j=0; j<=scc; ++j) ex[i][j]=0;
for(pair<int,int> now:rev){
if(!ex[belong[now.fi]][belong[now.se]]){
if(belong[now.fi]==belong[now.se]) continue; //不能建自环鸭
ex[belong[now.fi]][belong[now.se]]=1;
E[belong[now.fi]].eb(belong[now.se]);
++indeg[belong[now.se]];
}
}
toposort();
int ans=0;
for(int i=1; i<=scc; ++i) uax(ans,dp[i]);
cout<<ans<<'\n';
}
return 0;
}