题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2767
题意:问一个图至少加多少条边后能成为强连通的
我们用Tarjan处理完图的强连通分量以后,就将每一个强连通分量缩成一个点,新的图之后就成为一个有向无环图
让这个有向无环图成为强连通的方法就是加上入度为0的点的个数 和 出度为0的点的个数取max
现在来看看怎么连这个有向无环图 是使这个图强连通
对于一个出度为0 的点u 我们添加一个边(u,v) v为入度为0的点 然后更新u,v的出入度
最后到没有出度为0的点 或者 入度为0的点 那么剩下的点可以随便连图上任何一个点
代码:
#include <bits/stdc++.h>
#define sf scanf
#define pf printf
using namespace std;
const int maxn = 20000 + 50;
vector<int> Adj[maxn];
stack<int> Stack;
int low[maxn],dfn[maxn],inStack[maxn],belong[maxn],ins[maxn],ous[maxn];
int TOT,Block_CNT;
void DFS(int u){
dfn[u] = low[u] = TOT++;
Stack.push(u);inStack[u] = 1;
int len = Adj[u].size(),v;
for(int i = 0;i < len;++i){
v = Adj[u][i];
if(dfn[v] == -1){
DFS(v);
low[u] = min(low[u],low[v]);
}
else if(inStack[v]) low[u] = min(low[u],dfn[v]);
}
if(low[u] == dfn[u]){
int tmp;
do{
tmp = Stack.top();Stack.pop();
inStack[tmp] = false;
belong[tmp] = Block_CNT;
}while(tmp != u);
Block_CNT++;
}
}
int main(){
int T;sf("%d",&T);
while(T--){
memset(dfn,-1,sizeof dfn);
memset(inStack,0,sizeof inStack);
memset(ins,0,sizeof ins);
memset(ous,0,sizeof ous);
TOT = 1;Block_CNT = 0;
int n,m;sf("%d %d",&n,&m);
for(int i = 1;i <= n;++i) Adj[i].clear();
for(int i = 0;i < m;++i){
int u,v;sf("%d %d",&u,&v);
Adj[u].push_back(v);
}
for(int i = 1;i <= n;++i)
if(dfn[i] == -1) DFS(i);
for(int i = 1;i <= n;++i){
int len = Adj[i].size();
for(int j = 0;j < len;++j){
int v = Adj[i][j];
if(belong[i] != belong[v]) ous[belong[i]]++,ins[belong[v]]++;
}
}
int cnt_ous = 0,cnt_ins = 0;
for(int i = 0;i < Block_CNT;++i){
if(ins[i] == 0) cnt_ins++;
if(ous[i] == 0) cnt_ous++;
}
if(Block_CNT == 1) cnt_ous = 0,cnt_ins = 0;
pf("%d\n",max(cnt_ous,cnt_ins));
}
}