我们知道,要把一个非边双连通图构造成一个边双连通图,只需把这个图化简(边双连通分量缩点)成一个树,然后 找出叶子节点个数leaf,(leaf+1)/2就是要新添加的边数。
现在,对与有向图来说,我们需要求加最少的边,使得一个非强连通图变成一个强连通图,最少的边数是多少?
同样的,我们需要把他化简(强连通分量缩点)成一个DAG图(有向无环图),然后找出入度为0的顶点个数in,和出度为0的顶点个数out,取他们的最大值就是需要添加的最少的边数。
对于一种特殊情况,若原图中本身就是一个强连通图,那么缩点后的DGA图就是一个孤立的点,in和out分别等于1,按上述方式求的答案为1,显然和正确答案0不同,所以,我们在此特判一下即可。
poj 1236
1 #include <cstdio> 2 #include <cstring> 3 #include <queue> 4 #include <algorithm> 5 #define _Clr(x, y) memset(x, y, sizeof(x)) 6 #define INF 0x3f3f3f3f 7 #define N 110 8 using namespace std; 9 10 struct Node 11 { 12 int to, next; 13 }edge[N*100]; 14 int head[N], tot; 15 int dfn[N], low[N]; 16 int Sta[N], bleg[N]; 17 bool instack[N]; 18 int n, cnt, top, ght; 19 20 void Init() 21 { 22 cnt=tot=top=ght=0; 23 _Clr(head, -1); 24 _Clr(dfn, 0); 25 _Clr(instack, 0); 26 } 27 28 void Add_edge(int a, int b) 29 { 30 edge[tot].to = b; 31 edge[tot].next = head[a]; 32 head[a] = tot++; 33 } 34 35 void dfs(int u) 36 { 37 dfn[u]=low[u]=++cnt; 38 instack[u] = true; 39 Sta[top++] = u; 40 for(int i=head[u]; i!=-1; i=edge[i].next) 41 { 42 int v = edge[i].to; 43 if(!dfn[v]) 44 { 45 dfs(v); 46 low[u] = min(low[u], low[v]); 47 } 48 else if(instack[v]) low[u] = min(low[u], dfn[v]); 49 } 50 if(low[u]==dfn[u]) 51 { 52 ght++; 53 // printf("Num:%d ",ght); 54 int v; 55 do 56 { 57 v = Sta[--top]; 58 // printf("%d ", v); 59 instack[v] = false; 60 bleg[v] = ght; 61 }while(u != v); 62 // puts(""); 63 } 64 } 65 66 int inde[N], outde[N]; 67 void Tarjan() 68 { 69 for(int i=1; i<=n; i++) 70 if(!dfn[i]) dfs(i); 71 72 _Clr(inde, 0); 73 _Clr(outde, 0); 74 for(int u=1; u<=n; u++) 75 for(int i=head[u]; i!=-1; i=edge[i].next) 76 { 77 int v = edge[i].to; 78 if(bleg[v] != bleg[u]) 79 inde[bleg[v]]++, outde[bleg[u]]++; 80 } 81 } 82 83 void Solved() 84 { 85 int a=0, b=0; 86 if(ght==1) 87 printf("1 0 "); 88 else 89 { 90 for(int i=1; i<=ght; i++) 91 { 92 if(inde[i]==0) a++; 93 if(outde[i]==0) b++; 94 } 95 printf("%d %d ", a, max(a, b)); 96 } 97 } 98 int main() 99 { 100 int b; 101 while(~scanf("%d", &n)) 102 { 103 Init(); 104 for(int i=1; i<=n; i++) 105 { 106 while(scanf("%d", &b) && b) 107 Add_edge(i, b); 108 } 109 Tarjan(); 110 Solved(); 111 } 112 return 0; 113 }