給定一個有向圖,問最少增長多少條邊後變成強連通圖
tarjan求求強連通份量並縮點,若是強連通份量個數爲1,則須要邊數爲0,
不然爲縮點後點入度和出度的最大值,
證實:當入度或者出度不爲0時,則能夠經過傳遞性使其相同,因此只須要考慮入度或者出度爲0的點
便可。由於要求增長儘可能少的邊,因此將入度和出度都爲0的點相連,邊的方向爲出度爲0的指向入度爲0的頂點。
當入度爲0或者出度爲0的點有剩餘時,則任意取一個點進行連邊。
因此當有向圖爲強連通圖時答案爲0,不然最小值爲入度和入度的最大值node
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 20005; const int maxm = 100005; struct node{ int v,next; }edge[maxm]; int head[maxn],low[maxn],dfn[maxn],sta[maxn],in[maxn],out[maxn],belong[maxn],vis[maxm]; int Time,id,top,num,total; void add_edge(int u,int v){ edge[id].v = v;edge[id].next = head[u];head[u] = id++; } void tarjan(int u){ low[u] = dfn[u] = ++Time; sta[top++] = u;in[u] = 1; for(int id = head[u]; id != -1; id = edge[id].next){ int v = edge[id].v; if(!dfn[v]){ tarjan(v); if( low[u] < low[v])total++; low[u] = min(low[u],low[v]); } else if( in[v] )low[u] = min(low[u],low[v]); } if( low[u] == dfn[u]){ num ++; do{ int t = sta[--top]; in[t] = 0; belong[t] = num; }while( sta[top] != u); } } int main(){ int t; int n,m; int u,v; int cnt; scanf("%d",&t); while( t-- ){ scanf("%d%d",&n,&m); memset(head,-1,sizeof(head)),id = 0; while( m-- ){ scanf("%d%d",&u,&v); add_edge(u,v); } memset(dfn,0,sizeof(dfn)); Time = num = total = cnt = 0; for(int i = 1; i <= n;i++){ if(!dfn[i]) tarjan(i); } if( num == 1){puts("0");continue;} memset(in,0,sizeof(in)); memset(out,0,sizeof(out)); for(int u = 1; u <= n; u++){ for(int id = head[u]; id != -1; id = edge[id].next){ int v = edge[id].v; if( belong[u] != belong[v]){ in[belong[v]]++;out[belong[u]]++; } } } int indeg = 0,outdeg = 0; for(int i = 1; i <= num; i++){ if( !in[i])indeg ++; if( !out[i])outdeg++; } printf("%d\n",indeg > outdeg ? indeg : outdeg); } return 0; }