题意:让所有点强连通需要最少连多少条边?
思路:缩点,求出每个强连通分量的入度和出度,如果强连通分量的入度为0,则incnt++,如果强连通分量的出度为0,则outcnt++,取max(incnt,outcnt)就是答案。因为一个强连通的图中,每个点的入度和出度都是
≥
1的。所有最多只要连max(incnt,outcnt)条线,因为可以将出度为0的点连上入度为0的点。
http://acm.hdu.edu.cn/showproblem.php?pid=3836
#include <map>
#include <set>
#include <queue>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define rep(i,a,b) for(int i = a ; i <= b ; i ++)
#define rrep(i,a,b) for(int i = b ; i >= a ; i --)
#define repE(p,u) for(Edge * p = G[u].first ; p ; p = p -> next)
#define cls(a,x) memset(a,x,sizeof(a))
using namespace std;
typedef long long LL;
const int MOD = 1e9+7;
const int INF = 0x3f3f3f3f;
const int MAXN = 2e4+5;
const int MAXE = 5e4+5;
struct Edge {
int to;
Edge * next ;
}E[MAXE], * EE;
struct Gragh {
Edge * first ;
}G[MAXN];
int T,n,m;
int Stack[MAXN] ;
bool InStack[MAXN];
int dfn[MAXN] , low[MAXN] , num[MAXN] , belong[MAXN];
int idx,top,scc;
void addedge(int u,int v) {
EE->to = v ; EE->next = G[u].first ; G[u].first = EE ++;
}
void init() {
EE = E; idx = top = scc = 0;
cls(G,0); cls(dfn,0); cls(InStack,0);
}
void tarjan(int u) {
int v;
dfn[u] = low[u] = ++idx;
Stack[top++] = u;
InStack[u] = true;
repE(p,u) {
v = p -> to;
if(!dfn[v]) {
tarjan(v);
if(low[u] > low[v]) low[u] = low[v];
}
else if(InStack[v] && low[u] > dfn[v])
low[u] = dfn[v];
}
if(low[u] == dfn[u]) {
scc ++;
do {
v = Stack[--top];
InStack[v] = false;
belong[v] = scc;
num[scc] ++;
} while(v != u) ;
}
}
int X[MAXE];
int Y[MAXE];
int indegree[MAXN];
int outdegree[MAXN];
void input() {
int u,v;
rep(i,1,m) {
scanf("%d %d",&u,&v);
X[i] = u; Y[i] = v;
addedge(u,v);
}
}
void solve() {
rep(i,1,n) {
if(!dfn[i]) tarjan(i);
}
if(scc == 1) {
puts("0");
}
else {
int incnt = 0 , outcnt = 0;
cls(indegree,0); cls(outdegree,0);
rep(i,1,m) {
if(belong[X[i]] != belong[Y[i]]) {
indegree[belong[Y[i]]] ++;
outdegree[belong[X[i]]] ++;
}
}
rep(i,1,scc) {
if(indegree[i] == 0) incnt ++;
if(outdegree[i] == 0) outcnt ++;
}
printf("%d\n",max(incnt,outcnt));
}
}
int main(void) {
while(~scanf("%d %d",&n,&m)) {
init();
input();
solve();
}
return 0;
}