强连通从入门到精通

资料:

有向图的强连通分量 kuangbin

有向图强连通分量的Tarjan算法

一、模板

(1)tarjan模板

 1 #define N 30100  
 2 //N为最大点数  
 3 #define M 150100  
 4 //M为最大边数  
 5 int n, m;//n m 为点数和边数  
 6   
 7 struct Edge{  
 8     int from, to, nex;  
 9     bool sign;//是否为桥  
10 }edge[M<<1];  
11 int head[N], edgenum;  
12 void add(int u, int v){//边的起点和终点  
13     Edge E={u, v, head[u], false};  
14     edge[edgenum] = E;  
15     head[u] = edgenum++;  
16 }  
17   
18 int DFN[N], Low[N], Stack[N], top, Time; //Low[u]是点集{u点及以u点为根的子树} 中(所有反向弧)能指向的(离根最近的祖先v) 的DFN[v]值(即v点时间戳)  
19 int taj;//连通分支标号,从1开始  
20 int Belong[N];//Belong[i] 表示i点属于的连通分支  
21 bool Instack[N];  
22 vector<int> bcc[N]; //标号从1开始  
23   
24 void tarjan(int u ,int fa){    
25     DFN[u] = Low[u] = ++ Time ;    
26     Stack[top ++ ] = u ;    
27     Instack[u] = 1 ;    
28   
29     for (int i = head[u] ; ~i ; i = edge[i].nex ){    
30         int v = edge[i].to ;    
31         if(DFN[v] == -1)  
32         {    
33             tarjan(v , u) ;    
34             Low[u] = min(Low[u] ,Low[v]) ;  
35             if(DFN[u] < Low[v])  
36             {  
37                 edge[i].sign = 1;//为割桥  
38             }  
39         }    
40         else if(Instack[v]) Low[u] = min(Low[u] ,DFN[v]) ;        
41     }    
42     if(Low[u] == DFN[u]){    
43         int now;  
44         taj ++ ; bcc[taj].clear();  
45         do{  
46             now = Stack[-- top] ;    
47             Instack[now] = 0 ;   
48             Belong [now] = taj ;  
49             bcc[taj].push_back(now);  
50         }while(now != u) ;  
51     }  
52 }  
53   
54 void tarjan_init(int all){  
55     memset(DFN, -1, sizeof(DFN));  
56     memset(Instack, 0, sizeof(Instack));  
57     top = Time = taj = 0;  
58     for(int i=1;i<=all;i++)if(DFN[i]==-1 )tarjan(i, i); //注意开始点标!!!  
59 }  
60 vector<int>G[N];  
61 int du[N];  
62 void suodian(){  
63     memset(du, 0, sizeof(du));  
64     for(int i = 1; i <= taj; i++)G[i].clear();  
65     for(int i = 0; i < edgenum; i++){  
66         int u = Belong[edge[i].from], v = Belong[edge[i].to];  
67         if(u!=v)G[u].push_back(v), du[v]++;  
68     }  
69 }  
70 void init(){memset(head, -1, sizeof(head)); edgenum=0;}  

二、练习

1、【CodeForces 427C】 Checkposts

题意:n(1<=n<=10^5)个城市,m(1<=m<=10^5)条单向的路,现在要放一些保安来管理这n个城市,如果在第i个城市放保安,需要花费a[i](0<=a[i]<=10^9)的钱,如果城市j满足【保安能从i走到j,同时能从j走回到i】那么放在城市i的保安能管理城市j。求在哪些城市放保安能将这n个城市全都治理到,并且所花的钱最少,输出花的钱以及放保安的方案数。

解题思路:模板题,求出每个连通分量的最小花费minx[taj],以及最小花费的个数maxn[taj],花的最少钱是minx[]的和,方案数就是maxn[]的乘积。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define ll __int64
 4 const int mod=1e9+7;
 5 #define N 301000 
 6 //N为最大点数  
 7 #define M 150100  
 8 //M为最大边数  
 9 int n, m;//n m 为点数和边数  
10   
11 struct Edge{  
12     int from, to, nex;  
13 }edge[N<<1];  
14 int head[N], edgenum;  
15 void add(int u, int v){//边的起点和终点  
16     Edge E={u, v, head[u]};  
17     edge[edgenum] = E;  
18     head[u] = edgenum++;  
19 }  
20   
21 int DFN[N], Low[N], Stack[N], top, Time; 
22 //Low[u]是点集{u点及以u点为根的子树}中
23 //(所有反向弧)能指向的(离根最近的祖先v)的DFN[v]值(即v点时间戳)  
24 int taj;//连通分支标号,从1开始  
25 int Belong[N];//Belong[i] 表示i点属于的连通分支  
26 bool Instack[N];   
27 ll pp[N], minx[N], maxn[N];
28 void tarjan(int u ,int fa){    
29     DFN[u] = Low[u] = ++ Time ;    
30     Stack[top ++ ] = u ;    
31     Instack[u] = 1 ;    
32   
33     for (int i = head[u] ; ~i ; i = edge[i].nex ){    
34         int v = edge[i].to ;    
35         if(DFN[v] == -1)  
36         {    
37             tarjan(v , u) ;    
38             Low[u] = min(Low[u] ,Low[v]) ;  
39         }    
40         else if(Instack[v]) Low[u] = min(Low[u] ,DFN[v]) ;        
41     }    
42     if(Low[u] == DFN[u]){    
43         int now;  
44         taj ++ ;
45         do{  
46             now = Stack[-- top] ;    
47             Instack[now] = 0 ;   
48             Belong [now] = taj ;   
49             if(minx[taj]>pp[now]) minx[taj]=pp[now], maxn[taj]=0;
50             if(minx[taj]==pp[now]) maxn[taj]++;
51         }while(now != u) ;  
52     }  
53 }  
54   
55 void tarjan_init(int all){  
56     memset(DFN, -1, sizeof(DFN));  
57     memset(Instack, 0, sizeof(Instack));  
58     memset(minx, 0x3f3f3f3f, sizeof(minx));
59     memset(maxn, 0, sizeof(maxn));
60     top = Time = taj = 0;  
61     for(int i=1;i<=all;i++)if(DFN[i]==-1 )tarjan(i, i); //注意开始点标!!!  
62 }  
63 void init(){memset(head, -1, sizeof(head)); edgenum=0;}  
64 int main(){
65         scanf("%d", &n);
66         init();
67         for(int i=1; i<=n; i++) scanf("%d", &pp[i]);
68         scanf("%d", &m);
69         int u, v;
70         for(int i=0; i<m; i++){
71             scanf("%d%d", &u, &v);
72             add(u, v);
73         }
74         tarjan_init(n);
75         ll ans=0, sum=1;
76         for(int i=1; i<=taj; i++){
77             ans+=minx[i];
78             sum = (sum*maxn[i])%mod;
79         }
80         printf("%I64d %I64d\n", ans, sum);
81     return 0;
82 }
View Code

2、【hdu 1827Proving Equivalences

题意:有n(1<=n<=1000)个人需要通知,小A每通知一个人就要花费a[i]的花费,有m(1<=m<=2000)组关系,每组关系只能单向联系,问小A至少需要通知几个人,要花费多少钱?

解题思路:连通分量缩点,一个连通分量只需通知一人,求出通知每个连通分量的人最少话费,入度为0的连通分量肯定要通知,因为没人通知他,否则就不用通知

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <string>
 6 #include <vector>
 7 using namespace std;
 8 #define N 30100  
 9 #define M 150100   
10 int n, m;
11   
12 struct Edge{  
13     int from, to, nex;  
14 }edge[N<<1];  
15 int head[N], edgenum;  
16 int a[N];
17 void add(int u, int v){//边的起点和终点  
18     Edge E={u, v, head[u]};  
19     edge[edgenum] = E;  
20     head[u] = edgenum++;  
21 }  
22   
23 int minx[N], DFN[N], Low[N], Stack[N], top, Time; //Low[u]是点集{u点及以u点为根的子树} 中(所有反向弧)能指向的(离根最近的祖先v) 的DFN[v]值(即v点时间戳)  
24 int taj;//连通分支标号,从1开始  
25 int Belong[N];//Belong[i] 表示i点属于的连通分支  
26 bool Instack[N];  
27 vector<int> bcc[N]; //标号从1开始  
28   
29 void tarjan(int u ,int fa){    
30     DFN[u] = Low[u] = ++ Time ;    
31     Stack[top ++ ] = u ;    
32     Instack[u] = 1 ;    
33   
34     for (int i = head[u] ; ~i ; i = edge[i].nex ){    
35         int v = edge[i].to ;    
36         if(DFN[v] == -1)  
37         {    
38             tarjan(v , u) ;    
39             Low[u] = min(Low[u] ,Low[v]) ;  
40         }    
41         else if(Instack[v]) Low[u] = min(Low[u] ,DFN[v]) ;        
42     }    
43     if(Low[u] == DFN[u]){    
44         int now;  
45         taj ++ ; bcc[taj].clear();  
46         int k=0x3f3f3f3f;
47         do{  
48             now = Stack[-- top] ;    
49             Instack[now] = 0 ;   
50             Belong [now] = taj ; 
51             k = min(k, a[now]);
52             bcc[taj].push_back(now);  
53         }while(now != u) ;  
54         minx[taj] = k;
55     }  
56 }  
57   
58 void tarjan_init(int all){  
59     memset(DFN, -1, sizeof(DFN));  
60     memset(Instack, 0, sizeof(Instack));  
61     top = Time = taj = 0;  
62     for(int i=1;i<=all;i++)if(DFN[i]==-1 )tarjan(i, i); //注意开始点标!!!  
63 }  
64 vector<int>G[N];  
65 int du[N];  
66 void suodian(){  
67     memset(du, 0, sizeof(du));
68     for(int i = 1; i <= taj; i++)G[i].clear();  
69     for(int i = 0; i < edgenum; i++){  
70         int u = Belong[edge[i].from], v = Belong[edge[i].to];  
71         //一开始我是这样求minx[]的,但是这里是枚举边的,没法处理单独的点,会wa 
72         /*minx[u] = min(minx[u], a[edge[i].from]);
73         minx[v] = min(minx[v], a[edge[i].to]);  */
74         if(u!=v)G[u].push_back(v), du[v]++;  
75     }  
76 }  
77 void init(){memset(head, -1, sizeof(head)); edgenum=0;}  
78 int main(){
79     int n, m, u, v;
80     while(~scanf("%d%d", &n, &m)){
81         init();
82         for(int i=1; i<=n; i++) scanf("%d", &a[i]);
83         for(int i=0; i<m; i++){
84             scanf("%d%d", &u, &v);
85             add(u, v);
86         }
87         tarjan_init(n);
88         suodian();
89         int num=0, ans=0;
90         for(int i=1; i<=taj; i++){
91             if(du[i]==0){
92                 num++, ans+=minx[i];
93             }
94         }
95         printf("%d %d\n", num, ans);
96     }
97     return 0;
98 }
View Code

3、【poj 2762Going from u to v or from v to u?

题意:n(0<n<1001)个城市,m(m<6000)条单向路,如果任意两个城市uv满足【u能走到v || v能走到u】就输出Yes,否则就输出No

解题思路:一个连通分量是肯定满足条件的,接下来就是判断任意两个连通分量之间是不是满足题意,这个好办,连通分量缩点,然后求缩点后形成的树的直径,如果直径的大小就是连通分量的个数,那就是Yes,也就是缩点后的连通分量是一条链,没有分支,否则必定有两个点之间是无法到达的

  1 #include <iostream>
  2 #include <algorithm>
  3 #include <cstdio>
  4 #include <cstring>
  5 #include <string>
  6 #include <vector>
  7 using namespace std;
  8 const int N=1e4+10;
  9 const int M=1e5+10;
 10 int n, m;
 11 struct Edge{
 12     int from, to, nxt;
 13 }edge[M<<1];
 14 int head[N], edgenum;
 15 
 16 void init(){
 17     memset(head, -1, sizeof(head));
 18     edgenum=0;
 19 }
 20 void add(int u, int v){
 21     Edge E = {u, v, head[u]};
 22     edge[edgenum] = E;
 23     head[u]=edgenum++;
 24 }
 25 int DFN[N],  Stack[N], Low[N], top, time;
 26 int taj;
 27 int Belong[N];
 28 bool Instack[N];
 29 void tarjan(int u, int fa){
 30     DFN[u] = Low[u] = ++time;
 31     Stack[top++] = u;
 32     Instack[u] = 1;
 33     
 34     for(int i=head[u]; ~i; i=edge[i].nxt){
 35         int v = edge[i].to;
 36         if(DFN[v]==-1){
 37             tarjan(v, u);
 38             Low[u] = min(Low[u], Low[v]);
 39         }
 40         else if(Instack[v]) Low[u] = min(Low[u], DFN[v]);
 41     }
 42     if(Low[u] == DFN[u]){
 43         taj++;
 44         int now;
 45         do{
 46             now = Stack[--top];
 47             Instack[now] = 0;
 48             Belong[now] = taj;
 49             
 50         }while(now != u);
 51     }
 52 }
 53 void tarjan_init(int all){
 54     memset(DFN, -1, sizeof(DFN));
 55     memset(Instack, 0, sizeof(Instack));
 56     top = time = taj = 0;
 57     for(int i=1; i<=all; i++){
 58         if(DFN[i]==-1) tarjan(i, i);
 59     }
 60 }
 61 vector<int>G[N];
 62 int du[N];
 63 void suodian(){
 64     memset(du, 0, sizeof(du));
 65     for(int i=1; i<=n; i++) G[i].clear();
 66     for(int i=0; i<edgenum; i++){
 67         int uu=Belong[edge[i].from], vv=Belong[edge[i].to];
 68         if(uu != vv){
 69             G[uu].push_back(vv);
 70             du[vv]++;
 71         }
 72     }
 73 }
 74 
 75 int dis[N], id, maxn, ans;
 76 void dfs(int u, int fa){
 77     for(int i=0; i<G[u].size(); i++){
 78         int v = G[u][i];
 79         if(v != fa){
 80             dis[v] = dis[u]+1;
 81             if(dis[v]>maxn){
 82                 id=v, maxn = dis[v], ans++;
 83             }
 84         }
 85         dfs(v, u);
 86     }
 87 }
 88 int main(){
 89     int t;
 90     scanf("%d", &t);
 91     while(t--){
 92         scanf("%d%d", &n, &m);
 93         init();
 94         int u, v;
 95         for(int i=0; i<m; i++){
 96             scanf("%d%d", &u, &v);
 97             add(u, v);
 98         }
 99         tarjan_init(n);
100         suodian();
101         ans = 0;
102         for(int i=1; i<=taj; i++) {
103             if(du[i]==0) id=i, ans++;
104         }
105         if(ans>1) {
106             printf("No\n");
107             continue;
108         }
109         memset(dis, 0, sizeof(dis));
110         dis[id] = 1;
111         maxn=1;
112         dfs(id, -1);
113         if(maxn==taj) printf("Yes\n");
114         else printf("No\n");
115     }
116     return 0;
117 }
View Code

4、【hdu 2767Proving Equivalences &&【hdu 3836Equivalent Sets &&POJ 1236Network of Schools 

题意:已知图上有n(n<=2*10^4)个点,m(m<=5*10^4)条单向边,问至少加几条边让整个图变成强连通。

解题思路:Tarjan入门经典题,用tarjan缩点,然后就变成一个有向无环图(DAG)了。 

我们要考虑的问题是让它变成强连通,让DAG变成强连通就是把尾和头连起来,也就是入度和出度为0的点。 

统计DAG入度和出度,然后计算头尾,最大的那个就是所求。

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <string>
 6 #include <vector>
 7 using namespace std;
 8 const int N=2*1e4+10;
 9 const int M=5*1e4+10;
10 int n, m;
11 struct Edge{
12     int from, to, nxt;
13 }edge[M];
14 int head[M], edgenum;
15 void init(){
16     memset(head, -1, sizeof(head));
17     edgenum = 0;
18 }
19 void addedge(int u, int v){
20     Edge E = {u, v, head[u]};
21     edge[edgenum] = E;
22     head[u] = edgenum++;
23 }
24 int DFN[N], Low[N], Belong[N], taj, top, time;
25 int Stack[N]; 
26 bool Instack[N];
27 void tarjan(int u, int fa){
28     DFN[u] = Low[u] = ++time;
29     Stack[top++]=u;
30     Instack[u]=1;
31     for(int i=head[u]; ~i; i=edge[i].nxt){
32         int v = edge[i].to;
33         if(DFN[v] == -1){
34             tarjan(v, u);
35             Low[u] = min(Low[u], Low[v]);
36         }
37         else if(Instack[v]) Low[u] = min(Low[u], DFN[v]);
38     }
39     if(DFN[u] == Low[u]){
40         int now;
41         taj++;
42         do{
43             now = Stack[--top];
44             Belong[now]=taj;
45             Instack[now]=0;
46         }while(now!=u);
47     }
48 }
49 void tarjan_init(int all){
50     memset(DFN, -1, sizeof(DFN));
51     memset(Instack, 0, sizeof(Instack));
52     taj = top = time = 0;
53     for(int i=1; i<=all; i++){
54         if(DFN[i] == -1) tarjan(i, i);
55     }
56 }
57 vector<int>G[N];
58 int du[N], chu[N];
59 void suodian(){
60     memset(du, 0, sizeof(du));
61     memset(chu, 0, sizeof(chu));
62     for(int i=1; i<=taj; i++) G[i].clear();
63     for(int i=0; i<edgenum; i++){
64         int uu=Belong[edge[i].from], vv=Belong[edge[i].to];
65         if(uu!=vv) G[uu].push_back(vv), du[vv]++, chu[uu]++;
66     }
67 }
68 int main(){
69     while(~scanf("%d%d", &n, &m)){
70         init();
71         int u, v;
72         for(int i=0; i<m; i++){
73             scanf("%d%d", &u, &v);
74             addedge(u, v);
75         }
76         tarjan_init(n);
77         suodian();
78         int num_chu=0, num_ru=0;
79         if(taj>1){
80             for(int i=1; i<=taj; i++){
81                 if(chu[i]==0) num_chu++;
82                 if(du[i]==0) num_ru++;
83             }
84         }
85         printf("%d\n", max(num_chu, num_ru));
86     }
87     return 0;
88 }
View Code

5、【ZOJ 3795Grouping

题意:有N个人,M条边,边(u,v)表示u的年龄不小于v,若把这N个人分为很多组,要求每一组中的年龄无法相互比较,求组数最小值。

偏序:图中每次删边后入度为0的点有多个,图中的点无法比较大小

全序:图中每次删边后入读为0的点只有一个,图上的点的先后关系只有一种。

解题思路:简单来说就是先缩点,记录点权值,求一条链上的最大权值和

  1 #include <iostream>
  2 #include <algorithm>
  3 #include <cstdio>
  4 #include <cstring>
  5 #include <string>
  6 #include <vector>
  7 #include <queue>
  8 using namespace std;
  9 const int N=1e5+10;
 10 const int M=3*1e5+10;
 11 int n, m;
 12 struct Edge{
 13     int from, to, nxt;
 14 }edge[M];
 15 int head[M], edgenum;
 16 void init(){
 17     memset(head, -1, sizeof(head));
 18     edgenum = 0;
 19 }
 20 void addedge(int u, int v){
 21     Edge E = {u, v, head[u]};
 22     edge[edgenum] = E;
 23     head[u] = edgenum++;
 24 }
 25 int DFN[N], Low[N], Belong[N], taj, top, Time;
 26 int Stack[N], num[N]; 
 27 bool Instack[N];
 28 void tarjan(int u, int fa){
 29     DFN[u] = Low[u] = ++Time;
 30     Stack[top++]=u;
 31     Instack[u]=1;
 32     for(int i=head[u]; ~i; i=edge[i].nxt){
 33         int v = edge[i].to;
 34         if(DFN[v] == -1){
 35             tarjan(v, u);
 36             Low[u] = min(Low[u], Low[v]);
 37         }
 38         else if(Instack[v]) Low[u] = min(Low[u], DFN[v]);
 39     }
 40     if(DFN[u] == Low[u]){
 41         int now;
 42         taj++;
 43         do{
 44             now = Stack[--top];
 45             Belong[now]=taj;
 46             Instack[now]=0;
 47             num[taj]++;
 48         }while(now!=u);
 49     }
 50 }
 51 void tarjan_init(int all){
 52     memset(DFN, -1, sizeof(DFN));
 53     memset(Instack, 0, sizeof(Instack));
 54     memset(num, 0, sizeof(num));
 55     taj = top = Time = 0;
 56     for(int i=1; i<=all; i++){
 57         if(DFN[i] == -1) tarjan(i, i);
 58     }
 59 }
 60 vector<int>G[N];
 61 int du[N], chu[N];
 62 void suodian(){
 63     memset(du, 0, sizeof(du));
 64     memset(chu, 0, sizeof(chu));
 65     for(int i=1; i<=taj; i++) G[i].clear();
 66     for(int i=0; i<edgenum; i++){
 67         int uu=Belong[edge[i].from], vv=Belong[edge[i].to];
 68         if(uu!=vv) G[uu].push_back(vv), du[vv]++, chu[uu]++;
 69     }
 70 }
 71 int ans, maxn, lian;
 72 int dis[N];
 73 queue<int>q;
 74 void BFS(){//拓扑排序 
 75     while(!q.empty()) q.pop();
 76     memset(dis, 0, sizeof(dis));
 77     maxn=0, lian=0;
 78     for(int i=1; i<=taj; i++){
 79         if(du[i]==0) {
 80             q.push(i);
 81             dis[i]=num[i];
 82         }
 83     }
 84     int u, v;
 85     while(!q.empty()){
 86         u=q.front();q.pop();
 87         if((int)G[u].size()==0){
 88             maxn = max(maxn, dis[u]);
 89             continue;
 90         }
 91         for(int i=0; i<G[u].size(); i++){
 92             int v=G[u][i];
 93             du[v]--;
 94             dis[v] = max(dis[v], dis[u]+num[v]);
 95             if(du[v]==0) q.push(v);
 96         }
 97     } 
 98     printf("%d\n", maxn);
 99 }
100 int main(){
101     int n, m;
102     while(~scanf("%d%d", &n, &m)){
103         init();
104         int u, v;
105         for(int i=0; i<m; i++){
106             scanf("%d%d", &u, &v);
107             addedge(u, v);
108         }
109         tarjan_init(n);
110         suodian();    
111         BFS();
112     }
113     return 0;
114 }
View Code

6、【ZOJ 3630Information

题意:n m表示n个节点,m(0<=m<=9900)条边,下面ma b 表示a-b点有一条有向边,给定有向图,删去一个点后,可以求出该图中强连通分量中最大的点数,问:删去某点后,最大点数 最小是多少(一个连通分量中至少要有2个点,否则该连通分量的点数记为0

解题思路:枚举删点,强连通求最大分量 

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <string>
 6 using namespace std;
 7 const int N=1e5+10;
 8 const int M=3*1e5+10;
 9 int n, m;
10 struct Edge{
11     int from, to, nxt;
12 }edge[M];
13 int head[M], edgenum;
14 void init(){
15     memset(head, -1, sizeof(head));
16     edgenum = 0;
17 }
18 void addedge(int u, int v){
19     Edge E = {u, v, head[u]};
20     edge[edgenum] = E;
21     head[u] = edgenum++;
22 }
23 int DFN[N], Low[N], Belong[N], taj, top, Time;
24 int Stack[N], num[N]; 
25 bool Instack[N];
26 int maxn_min, ans;
27 void tarjan(int u, int fa, int id){
28     DFN[u] = Low[u] = ++Time;
29     Stack[top++]=u;
30     Instack[u]=1;
31     for(int i=head[u]; ~i; i=edge[i].nxt){
32         int v = edge[i].to;
33         if(v==id) continue;
34         if(DFN[v] == -1){
35             tarjan(v, u, id);
36             Low[u] = min(Low[u], Low[v]);
37         }
38         else if(Instack[v]) Low[u] = min(Low[u], DFN[v]);
39     }
40     if(DFN[u] == Low[u]){
41         int now;
42         taj++;
43         do{
44             now = Stack[--top];
45             Belong[now]=taj;
46             Instack[now]=0;
47             num[taj]++;
48         }while(now!=u);
49         ans = max(ans, num[taj]);
50     }
51 }
52 void tarjan_init(int all, int id){
53     memset(DFN, -1, sizeof(DFN));
54     memset(Instack, 0, sizeof(Instack));
55     memset(num, 0, sizeof(num));
56     taj = top = Time = 0;
57     for(int i=0; i<all; i++){
58         if(i==id) continue;
59         if(DFN[i] == -1) tarjan(i, i, id);
60     }
61 }
62 int main(){
63     while(~scanf("%d%d", &n, &m)){
64         init();
65         int u, v;
66         for(int i=0; i<m; i++){
67             scanf("%d%d", &u, &v);
68             addedge(u, v);
69         }
70         maxn_min=1e9;
71         for(int i=0; i<n; i++){
72             ans=0;
73             tarjan_init(n, i);
74             if(ans<2) ans=0;
75             maxn_min=min(maxn_min, ans);
76         }
77         maxn_min = (maxn_min==1e9)?0:maxn_min;
78         printf("%d\n", maxn_min);
79     }
80     return 0;
81 }
View Code

 

转载于:https://www.cnblogs.com/yscc/p/5385030.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值