題目鏈接:Islands
題解:使用Tarjan算法找到每個強聯通分量,此時強聯通分量內部各點是相互可以到達的,那麼我們可以考慮把每個獨立的強聯通分量當作一個個獨立的點處理。到目前爲止,如果兩個點之間有邊,但是不屬於同一個強聯通分量的話,必然的我們需要增加一條邊,明白這個之後,計算出度和入度的最大值。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<stack>
#include<algorithm>
const int maxn = 1e5+10;
const int maxe = 1e6+10;
using namespace std;
int n,m;
int head[maxn];
int cnt,tot;
struct Edge{
int u,v,next;
}e1[maxe],e2[maxe];
int dfn[maxn],low[maxn];
stack<int> S;
int instack[maxn],belong[maxn],num[maxn];
int scc,index;//scc記錄強連通分量的個數
int in[maxn],out[maxn];
void addEdge(int u,int v,Edge* e1,int& cnt){
e1[cnt].u = u;e1[cnt].v = v;
e1[cnt].next = head[u];head[u] = cnt++;
}
void Tarjan(int u){
int v;
low[u] = dfn[u] = ++index;
S.push(u); instack[u] = 1;
for(int i = head[u]; i != -1; i = e1[i].next){
int v = e1[i].v;
if(!dfn[v]){
Tarjan(v);
low[u] = min(low[u],low[v]);
}else if(instack[v]){
low[u] = min(low[u],dfn[v]);
}
}
if(low[u] == dfn[u]){
++scc;
while(1){
int now = S.top();
S.pop();
instack[now] = 0;
belong[now] = scc;
num[scc]++;
if(now == u) break;
}
}
}
void solve(){
memset(dfn,0,sizeof(dfn));
memset(num,0,sizeof(num));
memset(instack,0,sizeof(instack));
scc = index = 0;
for(int i = 1; i <= n; i++){
if(!dfn[i]) Tarjan(i);
}
tot = 0;
memset(head,-1,sizeof(head));
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
int u,v;
for(int i = 0; i < cnt; i++){
u = belong[e1[i].u];
v = belong[e1[i].v];
if(u != v){
addEdge(u,v,e2,tot);
in[v]++;
out[u]++;
}
}
int a = 0,b = 0;
for(int i = 1; i <= scc; i++){
if(!in[i]) a++;
if(!out[i]) b++;
}
if(scc == 1) printf("0\n");
else printf("%d\n",max(a,b));
}
int main(){
int T;
int u,v;
scanf("%d",&T);
while(T--){
cnt = 0;
scanf("%d%d",&n,&m);
memset(head,-1,sizeof(head));
for(int i = 0; i < m; i++){
scanf("%d%d",&u,&v);
addEdge(u,v,e1,cnt);
}
solve();
}
return 0;
}