题意
给出一张有向图,求加入几条边后,原图变为一个强连通分量。
题解
首先求一下原图强连通分量个数,若为1答案则为0,否则对原图染色(缩点)。统计不同色块之间的入度和出度,答案为max(入度为0的色块数目,出度为0的色苦数目)。
因为对于每个出度为0的色块,为了组成强连通,每个色块必须要有一条出边,对于出度为0同理,所以答案为其中的最大值。
代码
#include<bits/stdc++.h>
using namespace std;
typedef double db;
typedef long long ll;
typedef unsigned long long ull;
const int nmax = 1e6+7;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const ull p = 67;
const ull MOD = 1610612741;
int N,M;
struct Tarjan{
int head[nmax],low[nmax],dfn[nmax],sstack[nmax],color[nmax],top,sccnum,dfnnum,tot,n;
int in[nmax],out[nmax];
bool visit[nmax];
struct edge{int to,nxt;}e[nmax<<1];
void init(int n){
memset(head,-1,sizeof head);
memset(dfn,0,sizeof dfn);
memset(color,0,sizeof color);
memset(visit,0,sizeof visit);
memset(in,0,sizeof in);
memset(out,0,sizeof out);
dfnnum = top = sccnum = tot = 0;
this->n = n;
}
void add_edge(int u,int v){
e[tot].to = v, e[tot].nxt = head[u]; head[u] = tot++;
}
void tarjan(int u){
low[u] = dfn[u] = ++dfnnum;
visit[u] = true;
sstack[++top] = u;
for(int i = head[u] ; i != -1; i = e[i].nxt){
int v = e[i].to;
if(!dfn[v]){
tarjan(v);
low[u] = min(low[u],low[v]);
}else if(visit[v]) low[u] = min(low[u], dfn[v]);
}
if(dfn[u] == low[u]){
visit[u] = false;
color[u] = ++ sccnum;
while(sstack[top] != u){
color[sstack[top]] = sccnum;
visit[sstack[top]] = false;
top--;
}
top--;
}
}
void dfs(int u){
visit[u] = true;
for(int i = head[u];i!=-1;i=e[i].nxt){
int v = e[i].to;
if(!visit[v]){
if(color[v] != color[u]) in[color[v]]++ ,out[color[u]]++;
dfs(v);
}else if(visit[v]){
if(color[v] != color[u]) in[color[v]]++ ,out[color[u]]++;
}
}
}
void start(){for(int i = 1;i<=n;++i) if(!dfn[i])
tarjan(i);}
int get_ans(){
if(sccnum == 1) return 0;
memset(visit,0,sizeof visit);
for(int i = 1;i<=n;++i) if(!visit[i]) dfs(i);
int notin = 0, notout = 0;
for(int i = 1;i<=sccnum;++i){
if(!in[i]) notin++;
if(!out[i]) notout++;
}
return max(notin,notout);
}
}solver;
int main(){
int t;
scanf("%d",&t);
while(t--){
scanf("%d %d",&N,&M);
solver.init(N);
int u,v;
for(int i = 1;i<=M;++i){
scanf("%d %d",&u,&v);
solver.add_edge(u,v);
}
solver.start();
printf("%d\n",solver.get_ans());
}
return 0;
}