#include <cstring> #include <cstdlib> #include <cstdio> 缩点的好处就是可以将乱七八糟的有向图 转化为无环的有向图#include <iostream> #include <algorithm> #include <cmath> #include <stack> using namespace std; #define MAXN 200010 #define clr(x,k) memset((x),(k),sizeof(x)) struct node { int st,to,next; } edge[MAXN]; int n,m,ct,id; int head[MAXN],low[MAXN],dfn[MAXN],belong[MAXN],in[MAXN],to[MAXN]; //DFN[i]表示 遍历到 i 点时是第几次dfs //Low[u] 表示 以u点为父节点的 子树 能连接到 [栈中] 最上端的点 的DFN值 bool instack[MAXN]; stack<int>q; void add_e(int i,int u,int v) { edge[i].st=u; edge[i].to=v; edge[i].next=head[u]; head[u]=i; } void tarjan(int i) { int j; dfn[i]=low[i]=++id; q.push(i); instack[i]=1; for(int u=head[i]; ~u; u=edge[u].next) { j=edge[u].to; if(dfn[j]==0) { tarjan(j); if(low[i]>low[j]) low[i]=low[j]; } else if(instack[j]&&low[i]>low[j]) low[i]=dfn[j]; } if(dfn[i]==low[i]) { ct++; do { j=q.top(); q.pop(); instack[j]=0; belong[j]=ct; } while(i!=j); } } int main() { int t,i,u,v,sum1,sum2; cin>>t; while(t--) { clr(head,-1); clr(low,0); clr(dfn,0); clr(belong,0); clr(in,0); clr(to,0); while(!q.empty()) q.pop(); cin>>n>>m; for(i=0; i<m; i++) { cin>>u>>v; add_e(i,u,v); } id=ct=0; for(i=1; i<=n; i++) { if(!dfn[i]) tarjan(i); } if(ct==1) { cout<<0<<endl; continue; } for(i=1; i<=ct; i++) { in[i]=to[i]=0; } for(i=0; i<m; i++)// 利用染色进行缩点 新的图的点的坐标为第i个强连通分量 { if(belong[edge[i].st]!=belong[edge[i].to]) { in[belong[edge[i].st]]++; to[belong[edge[i].to]]++; } } sum1=sum2=0; for(i=1; i<=ct; i++) { if(in[i]==0) sum1++; if(to[i]==0) sum2++; } cout<<max(sum1,sum2)<<endl; } return 0; }
时间: 2024-10-05 05:10:56