 /**//*
求最小加邊使有向圖變為強連通
先縮點,然后計算各個強連通分量的入度為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
搜索
最新評論

|
|