题意:给了一个有向图,然后问你最少添加几条边使得整个图的任意一个点可以到达所有的点
思路:换个模版写的这道题目,就是先缩点,对于缩过点的图,答案就是这些点的入度为0的点的个数和出度为0的点的个数的最大值
#include <stack>
#include <vector>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3fll;
const int maxn=20010;
vector<int>G[maxn];
stack<int>S;
int pre[maxn],lowlink[maxn],sccno[maxn],dfs_clock,scc_cnt,n,m;
void dfs(int u){
pre[u]=lowlink[u]=++dfs_clock;
S.push(u);
for(int i=0;i<G[u].size();i++){
int v=G[u][i];
if(!pre[v]){
dfs(v);
lowlink[u]=min(lowlink[u],lowlink[v]);
}else if(!sccno[v]) lowlink[u]=min(lowlink[u],pre[v]);
}
if(lowlink[u]==pre[u]){
scc_cnt++;
while(1){
int x=S.top();S.pop();
sccno[x]=scc_cnt;
if(x==u) break;
}
}
}
void find_scc(){
dfs_clock=scc_cnt=0;
memset(sccno,0,sizeof(sccno));
memset(pre,0,sizeof(pre));
for(int i=0;i<n;i++) if(!pre[i]) dfs(i);
}
int in[maxn],out[maxn];
int main(){
int T,u,v;
scanf("%d",&T);
while(T--){
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
for(int i=0;i<maxn;i++) G[i].clear();
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++){
scanf("%d%d",&u,&v);u--;v--;
G[u].push_back(v);
}
find_scc();
for(int i=0;i<n;i++){
for(unsigned int j=0;j<G[i].size();j++){
int t=G[i][j];
if(sccno[i]!=sccno[t]) out[sccno[i]]=1,in[sccno[t]]=1;
}
}
int ans1=0,ans2=0;
for(int i=1;i<=scc_cnt;i++){
if(in[i]==0) ans1++;
if(out[i]==0) ans2++;
}
if(scc_cnt==1) printf("0\n");
else printf("%d\n",max(ans1,ans2));
}
return 0;
}