/**//* 求最小加边使有向图变为强连通 先缩点,然后计算各个强连通分量的入度为0的个数,出度为0的个数 1) SCC=1, 不需添边 2) 添max( incnt, outcnt ) 贪心策略,汇基向点基连边,再添边的连接剩下的点基/汇基即可
*/ #include<cstdio> #include<cstring> #include<algorithm> #include<vector> using namespace std;
const int MAXN=20010;
int n,m; vector<int>G[2][MAXN]; int ID[MAXN],SCC,flag; int order[MAXN],cnt; int in[MAXN],out[MAXN];
void dfs(int u){ ID[u]=SCC; for(int i=0;i<G[flag][u].size();i++){ int v=G[flag][u][i]; if(!ID[v])dfs(v); } if(flag)order[++cnt]=u; }
int main(){ int T,a,b; scanf("%d",&T); while(T--){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ G[0][i].clear(); G[1][i].clear(); } while(m--){ scanf("%d%d",&a,&b); G[0][a].push_back(b); G[1][b].push_back(a); } flag=SCC=1; cnt=0; memset(ID,0,sizeof(ID)); for(int i=1;i<=n;i++) if(!ID[i])dfs(i); flag=SCC=0; memset(ID,0,sizeof(ID)); for(int i=cnt;i;i--){//注意是order[i] if(ID[order[i]])continue; SCC++; dfs(order[i]); } if(SCC==1){puts("0");continue;} memset(out,0,sizeof(out)); memset(in,0,sizeof(in)); for(int i=1;i<=n;i++) for(int j=0;j<G[0][i].size();j++){ int v=G[0][i][j]; if(ID[i]!=ID[v]){ in[ID[v]]++; out[ID[i]]++; } } int incnt=0,outcnt=0; for(int i=1;i<=SCC;i++){ if(in[i]==0)incnt++; if(out[i]==0)outcnt++; } printf("%d\n",max(incnt,outcnt)); } return 0; }
|
|
常用链接
随笔分类
Links
搜索
最新评论
|
|