连通分量___刷题记录

hdu 1269

判断是否存在一个强连通

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<stack>
 6 #include<vector>
 7 using namespace std;
 8 
 9 const int maxn = 10005;
10 vector<int> g[maxn];
11 stack<int> S;
12 
13 int n,m;
14 int sccno[maxn],low[maxn],pre[maxn];
15 int scc_cnt,dfs_clock;
16 
17 void init(){
18     while(!S.empty()) S.pop();
19     for(int i = 1;i <= n;i++) g[i].clear();
20     scc_cnt = dfs_clock = 0;
21     memset(sccno,0,sizeof(sccno));
22     memset(low,0,sizeof(low));
23     memset(pre,0,sizeof(pre));
24 }
25 
26 void dfs(int u){
27     low[u] = pre[u] = ++dfs_clock;
28     S.push(u);
29     for(int i = 0;i < g[u].size();i++){
30         int v = g[u][i];
31         if(!pre[v]){
32             dfs(v);
33             low[u] = min(low[v],low[u]);
34         }
35         else if(!sccno[v]) low[u] = min(low[u],pre[v]);
36     }
37     if(low[u] == pre[u]){
38         scc_cnt++;
39         for(;;){
40             int x = S.top();S.pop();
41             sccno[x] = scc_cnt;
42             if(x == u) break;
43         }
44     }
45 }
46 
47 void find_scc(){
48     for(int i = 1;i <= n;i++){
49         if(!pre[i]) dfs(i);
50     }
51     if(scc_cnt == 1) printf("Yes\n");
52     else printf("No\n");
53 }
54 
55 int main(){
56     while(scanf("%d %d",&n,&m) != EOF && (n ||m)){
57         init();
58         for(int i = 0;i < m;i++){
59             int u,v;
60             scanf("%d %d",&u,&v);
61             g[u].push_back(v);
62         }
63         find_scc();
64     }
65     return 0;
66 }
View Code

la 4287

白书上的例题

给一张图,问最少需要添加多少条边变成强连通

先求一遍强连通,然后把每一个强连通分量缩成一个点,再扫一遍边,如果发现一条边的两端u,v属于不同的强连通分量,如果是u--->v,那么in[scc[v]]++,out[scc[u]++;

最后统计入度为0的强连通分量个数a,出度为0的b,max(a,b)即为添加的最少边数

 

因为对于一个强连通,每一个点的入度至少为1.出度也至少为1,添加max(a,b)条边,能够满足这个条件

 

----不知道为什么用vector存图写的wa了,换成邻接表就过了

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<iostream>
  4 #include<algorithm>
  5 #include<stack>
  6 using namespace std;
  7 
  8 const int maxn = 20005;
  9 int first[maxn];
 10 int low[maxn],pre[maxn],sc[maxn];
 11 int din[maxn],dout[maxn];
 12 int n,m;
 13 int ecnt,scnt,dfs_clock;
 14 stack<int> S;
 15 
 16 struct Edge{
 17     int v,next;
 18 }e[3*maxn];
 19 
 20 void init(){
 21     ecnt = 0;
 22     memset(first,-1,sizeof(first));
 23     memset(din,0,sizeof(din));
 24     memset(dout,0,sizeof(dout));
 25 }
 26 
 27 void addedges(int u,int v){
 28     e[ecnt].v = v;
 29     e[ecnt].next = first[u];
 30     first[u] = ecnt++;
 31 }
 32 
 33 void dfs(int u){
 34     low[u] = pre[u] = ++dfs_clock;
 35     S.push(u);
 36     for(int i = first[u];~i;i = e[i].next){
 37         int v = e[i].v;
 38         if(!pre[v]){
 39             dfs(v);
 40             low[u] = min(low[u],low[v]);
 41         }
 42         else if(!sc[v]) low[u] = min(low[u],pre[v]);
 43     }
 44     if(pre[u] == low[u]){
 45         scnt++;
 46         for(;;){
 47             int x = S.top();S.pop();
 48             sc[x] = scnt;
 49             if(x == u) break;
 50         }
 51     }
 52 }
 53 
 54 void find_scc(){
 55     while(!S.empty()) S.pop();
 56     memset(low,0,sizeof(low));memset(pre,0,sizeof(pre));
 57     memset(sc,0,sizeof(sc));
 58     dfs_clock = scnt = 0;
 59     for(int i = 1;i <= n;i++) if(!pre[i]) dfs(i);
 60 }
 61 
 62 int main(){
 63     int T;
 64     scanf("%d",&T);
 65     while(T--){
 66         scanf("%d %d",&n,&m);
 67         init();
 68         for(int i = 1;i <= m;i++){
 69             int u,v;
 70             scanf("%d %d",&u,&v);
 71             addedges(u,v);
 72         }
 73         find_scc();
 74         if(scnt == 1){
 75             printf("0\n");
 76             continue;
 77         }
 78         for(int u = 1;u <= n;u++){
 79             for(int i = first[u];~i;i = e[i].next){
 80                 int v = e[i].v;
 81                 if(sc[u] != sc[v]){
 82                     din[sc[v]]++;
 83                     dout[sc[u]]++;
 84                 }
 85             }
 86         }
 87         
 88     //    printf("scnt = %d\n",scnt);
 89     //    for(int i = 1;i <= scnt;i++)
 90     //    printf("din[%d] = %d  dout[%d] = %d\n",i,din[i],i,dout[i]);
 91         
 92         int a = 0,b = 0;
 93         for(int i = 1;i <= scnt;i++){
 94             if(din[i] == 0) a++;
 95             if(dout[i] == 0) b++;
 96         }
 97         printf("%d\n",max(a,b));
 98     }
 99     return 0;
100 }
View Code

 

uva 11324

先求一遍强连通,再缩点,每个点的权值为这个强连通分量里面的节点个数,就可以转化成DAG上的动态规划来做了

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<iostream>
  4 #include<algorithm>
  5 #include<stack>
  6 #include<vector>
  7 using namespace std;
  8 
  9 const int maxn = 5005;
 10 int n,m;
 11 int first[maxn];
 12 int sc[maxn],scn[maxn],low[maxn],pre[maxn];
 13 int scnt,ecnt,dfs_clock;
 14 int dp[maxn];
 15 
 16 int first1[maxn];
 17 int ecnt1;
 18 
 19 struct Edge{
 20     int v,next;
 21 }e[maxn*10];
 22 
 23 Edge e1[maxn*10];
 24 
 25 stack<int> S;
 26 
 27 void init(){
 28     ecnt = ecnt1 = 0;
 29     memset(first,-1,sizeof(first));
 30     memset(first1,-1,sizeof(first1));
 31     memset(dp,0,sizeof(dp));
 32 }
 33 
 34 void addedges(int u,int v){
 35     e[ecnt].v = v;
 36     e[ecnt].next = first[u];
 37     first[u] = ecnt++;
 38 }
 39 
 40 void addedges1(int u,int v){
 41     e1[ecnt1].v = v;
 42     e1[ecnt1].next = first1[u];
 43     first1[u] = ecnt1++;
 44 }
 45 
 46 void dfs(int u){
 47     low[u] = pre[u] = ++dfs_clock;
 48     S.push(u);
 49     for(int i = first[u];~i;i = e[i].next){
 50         int v = e[i].v;
 51         if(!pre[v]){
 52             dfs(v);
 53             low[u] = min(low[u],low[v]);
 54         }
 55         else if(!sc[v]) low[u] = min(low[u],pre[v]);
 56     }
 57     if(pre[u] == low[u]){
 58         scnt++;
 59         for(;;){
 60             int x = S.top();S.pop();
 61             sc[x] = scnt;
 62             scn[scnt]++;
 63             if(x == u) break;
 64         }
 65     }
 66 }
 67 
 68 void find_scc(){
 69     while(!S.empty()) S.pop();
 70     scnt = dfs_clock = 0;
 71     memset(low,0,sizeof(low));memset(pre,0,sizeof(pre));
 72     memset(sc,0,sizeof(sc));memset(scn,0,sizeof(scn));
 73     
 74     for(int i = 1;i <= n;i++) if(!pre[i]) dfs(i);
 75 }
 76 
 77 int solve(int p){
 78     if(dp[p]) return dp[p];
 79     for(int i = first1[p];~i;i = e1[i].next){
 80         int v = e1[i].v;
 81         dp[p] = max(dp[p],solve(v));
 82     }
 83     return dp[p] = dp[p] + scn[p];
 84 }
 85 
 86 
 87 int main(){
 88     int T;
 89     scanf("%d",&T);
 90     while(T--){
 91         init();
 92         scanf("%d %d",&n,&m);
 93         for(int i = 0;i < m;i++ ){
 94             int u,v;
 95             scanf("%d %d",&u,&v);
 96             addedges(u,v);
 97         }
 98         find_scc();
 99         
100         for(int u = 1;u <= n;u++){
101             for(int i = first[u];~i;i = e[i].next){
102                 int v = e[i].v;
103                 if(sc[u] != sc[v]) addedges1(sc[u],sc[v]);
104             }
105         }
106         
107 
108         int ans = 0;
109         for(int i = 1;i <= scnt;i++) ans = max(ans,solve(i));
110         printf("%d\n",ans);
111     }
112     return 0;
113 }
View Code

 

poj 1236

和 la 4287一样,再多一个问题,就是输出入度为0的强连通分量有多少个

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<stack>
 6 using namespace std;
 7 
 8 const int maxn = 1005;
 9 int n;
10 stack<int> S;
11 
12 int first[maxn];
13 int low[maxn],pre[maxn],sc[maxn];
14 int scnt,ecnt,dfs_clock;
15 int din[maxn],dout[maxn];
16 
17 struct Edge{
18     int v,next;
19 }e[maxn*50];
20 
21 void init(){
22     ecnt = 0;
23     memset(first,-1,sizeof(first));
24     memset(din,0,sizeof(din));
25     memset(dout,0,sizeof(dout));
26 }
27 
28 void addedges(int u,int v){
29     e[ecnt].v = v;
30     e[ecnt].next = first[u];
31     first[u] = ecnt++;
32 }
33 
34 void dfs(int u){
35     low[u] = pre[u] = ++dfs_clock;
36     S.push(u);
37     for(int i = first[u];~i;i = e[i].next){
38         int v = e[i].v;
39         if(!pre[v]){
40             dfs(v);
41             low[u] = min(low[u],low[v]);
42         }
43         else if(!sc[v]) low[u] = min(low[u],pre[v]);
44     }
45     
46     if(pre[u] == low[u]){
47         scnt++;
48         for(;;){
49             int x = S.top();S.pop();
50             sc[x] = scnt;
51             if(x == u) break;
52         }
53     }
54 }
55 
56 void find_scc(){
57     scnt = dfs_clock = 0;
58     memset(low,0,sizeof(low));memset(pre,0,sizeof(pre));
59     memset(sc,0,sizeof(sc));
60     for(int i = 1;i <= n;i++) if(!pre[i]) dfs(i);
61 }
62 int main(){
63     while(scanf("%d",&n) != EOF){
64         init();
65         for(int i = 1;i <= n;i++){
66             int a;
67             while(scanf("%d",&a) != EOF && a){
68                 addedges(i,a);
69             }
70         }
71         find_scc();
72         if(scnt == 1){
73             printf("1\n0\n");
74             continue;
75         }
76         
77         for(int u = 1;u <= n;u++){
78             for(int i = first[u];~i;i = e[i].next){
79                 int v = e[i].v;
80                 if(sc[u] != sc[v]){
81                     din[sc[v]]++;
82                     dout[sc[u]]++;
83                 }
84             }
85         }
86         
87         int c1 = 0,c2 = 0;
88         for(int i = 1;i <= scnt;i++){
89             if(din[i] == 0) c1++;
90             if(dout[i] == 0) c2++;
91         }
92         printf("%d\n%d\n",c1,max(c1,c2));
93     }
94     return 0;
95 }
View Code

 zoj 2588

无向图求桥,注意一下重边

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<stack>
 6 using namespace std;
 7 
 8 const int maxn = 50005;
 9 int n,m;
10 int first[maxn];
11 int low[maxn],pre[maxn],ans[maxn];
12 
13 int ecnt,cnt,dfs_clock;
14 
15 struct Edge{
16     int v,next,id;
17     int tag;
18 }e[maxn*10];
19 
20 void init(){
21     ecnt = cnt = dfs_clock = 0;
22     memset(first,-1,sizeof(first));
23     memset(low,0,sizeof(low));memset(pre,0,sizeof(pre));
24     memset(ans,0,sizeof(ans));
25 }
26 
27 void addedges(int u,int v,int id){
28     int i;
29     for( i = first[u];~i;i = e[i].next){
30         if(e[i].v == v) break;
31     }
32     if(i != -1){
33         e[i].tag = 1;//如果存边的时候发现有重边,则这条边不会成为桥,标记出来,不用再储存这条边 
34         return;
35     }
36     e[ecnt].tag = 0;
37     e[ecnt].v = v;
38     e[ecnt].next = first[u];
39     e[ecnt].id = id;
40     first[u] = ecnt++;
41 }
42 
43 void tarjan(int u,int fa){
44     low[u] = pre[u] = ++dfs_clock;
45     for(int i = first[u];~i;i = e[i].next){
46         int v = e[i].v;
47         if(v == fa) continue;
48         if(!pre[v]){
49             tarjan(v,u);
50             low[u] = min(low[u],low[v]); 
51             if(low[v] > pre[u] && e[i].tag == 0){
52                 ans[cnt++] = e[i].id;
53             }
54         }
55         else low[u] = min(low[u],pre[v]);
56     }
57 } 
58 
59 int main(){
60     int T;
61     scanf("%d",&T);
62     while(T--){
63         init();
64         scanf("%d %d",&n,&m);
65         for(int i = 1;i <= m;i++){
66             int u,v;
67             scanf("%d %d",&u,&v);
68             addedges(u,v,i);addedges(v,u,i);
69         }
70         tarjan(1,0);
71         printf("%d\n",cnt);
72         if(cnt){
73             sort(ans,ans+cnt);
74             printf("%d",ans[0]);
75             for(int i = 1;i < cnt;i++) printf(" %d",ans[i]);
76             printf("\n");
77         }
78         if(T) printf("\n");
79     }
80     return 0;
81 }
View Code

 

poj 3352  边双连通

给定一张无向图,使得删掉任意一条边之后,整张图还是连通的至少需要添加多少条边

先用tarjan()求一下每个节点的low,用low的值来缩点,因为在同一个连通分量上的节点的low值都是相同的,

无向图的度数的定义是,这个节点连有几条边,它的度数就是几

然后再扫一遍边,如果这条边的两端的low值不同,则d[low[v]]++,d[low[u]]不用++,因为是无向图,在存边的时候就正向反向的边都存了

所以只需要加一个

然后求出度数为1的块有ans个

那么加(ans+1)/2条边就可以了

是因为将度数为1的块两两连接起来,即为(ans+1)/2

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<vector>
 6 using namespace std;
 7 
 8 const int maxn = 1005;
 9 int n,m;
10 int d[maxn];
11 int low[maxn],pre[maxn];
12 int first[maxn];
13 int ecnt,dfs_clock;
14 
15 struct Edge{
16     int v,next;
17 }e[10*maxn];
18 
19 void init(){
20     ecnt = dfs_clock = 0;
21     memset(first,-1,sizeof(first));
22     memset(low,0,sizeof(low));memset(pre,0,sizeof(pre));
23     memset(d,0,sizeof(d));
24 }
25 
26 void addedges(int u,int v){
27     e[ecnt].v = v;
28     e[ecnt].next = first[u];
29     first[u] = ecnt++;
30 }
31 
32 void tarjan(int u,int fa){
33     low[u] = pre[u] = ++dfs_clock;
34     for(int i = first[u];~i;i = e[i].next){
35         int v = e[i].v;
36         if(v == fa) continue;
37         if(!pre[v]){
38             tarjan(v,u);
39             low[u] = min(low[u],low[v]);
40         }
41         else if(v != fa) low[u] = min(low[u],pre[v]);
42     }
43 }
44 
45 int main(){
46     while(scanf("%d %d",&n,&m) != EOF){
47         init();
48         for(int i = 1;i <= m;i++){
49             int u,v;
50             scanf("%d %d",&u,&v);
51             addedges(u,v);addedges(v,u);
52         }
53         tarjan(1,-1);
54         
55     //    for(int i = 1;i <= n;i++)
56     //    printf("pre[%d] = %d  low[%d] = %d\n",i,pre[i],i,low[i]);
57         
58         for(int u = 1;u <= n;u++){
59             for(int i = first[u];~i;i = e[i].next){
60                 int v = e[i].v;
61                 if(low[u] != low[v])    d[low[v]]++;
62             }
63         }
64         
65     //    for(int i = 1;i <= n;i++)
66      //   printf("d[%d] = %d\n",i,d[i]);
67         
68         int ans = 0;
69         for(int i = 1;i <= n;i++) if(d[i]== 1) ans++;
70         printf("%d\n",(ans+1)/2);
71     }
72     return 0;
73 }
View Code

 

hdu 1827

先求一遍强连通,然后缩点

找入度为0的点就是需要传递消息的块,找出这个块里面花费最少的,再累加起来

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<stack>
 6 using namespace std;
 7 
 8 const int maxn = 1005;
 9 const int INF = 1000000005;
10 int first[maxn];
11 int n,m;
12 int scnt,dfs_clock,ecnt;
13 int low[maxn],pre[maxn],sc[maxn];
14 int in[maxn],a[maxn];
15 int cost[maxn];
16 stack<int> S;
17 
18 struct Edge{
19     int v,next;
20 }e[10*maxn];
21 
22 void init(){
23     ecnt = 0;
24     memset(first,-1,sizeof(first));
25     memset(in,0,sizeof(in));
26     memset(a,0,sizeof(a));
27     for(int i = 1;i <= n;i++) cost[i] = INF;
28 }
29 
30 void addedges(int u,int v){
31     e[ecnt].v = v;
32     e[ecnt].next = first[u];
33     first[u] = ecnt++;
34 }
35 
36 void dfs(int u){
37     low[u] = pre[u] = ++dfs_clock;
38     S.push(u);
39     for(int i = first[u];~i;i = e[i].next){
40         int v = e[i].v;
41         if(!pre[v]){
42             dfs(v);
43             low[u] = min(low[u],low[v]);
44         }
45         else if(!sc[v]) low[u] = min(low[u],pre[v]);
46     }
47     if(pre[u] == low[u]){
48         scnt++;
49         for(;;){
50             int x = S.top();S.pop();
51             sc[x] = scnt;
52             if(x == u) break;
53         }
54     }
55 }
56 
57 void find_scc(){
58     scnt = dfs_clock = 0;
59     memset(low,0,sizeof(low));memset(pre,0,sizeof(pre));
60     memset(sc,0,sizeof(sc));
61     
62     for(int i = 1;i <= n;i++) if(!pre[i]) dfs(i);
63 }
64 
65 int main(){
66     while(scanf("%d %d",&n,&m) != EOF){
67         init();
68         for(int i = 1;i <= n;i++) scanf("%d",&a[i]);
69         for(int i = 0;i < m;i++){
70             int u,v;
71             scanf("%d %d",&u,&v);
72             addedges(u,v);
73         }
74         find_scc();
75         for(int u = 1;u <= n;u++){
76             for(int i = first[u];~i;i = e[i].next){
77                 int v = e[i].v;
78                 if(sc[u] != sc[v]) in[sc[v]]++;
79             }
80         }
81         
82         for(int i = 1;i <= n;i++){
83             if(in[sc[i]] == 0) cost[sc[i]] = min(cost[sc[i]],a[i]);
84         }
85         
86         int ans = 0,res = 0;
87         for(int i = 1;i <= scnt;i++){
88             if(in[i] == 0) ans += cost[i],res++;
89         }
90         printf("%d %d\n",res,ans);
91     }
92     return 0;
93 }
View Code

 

hdu 3072

给定一个定点,到其他所有点的花费最小

先求一遍强连通,再缩点,更新不同的连通块之间的最小的花费,如果某一块的d[i] = INF,说明其他的块都不能到达它

则说明它的入度为0,为给定的那个定点

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<stack>
 6 using namespace std;
 7 
 8 const int maxn = 50005;
 9 const int INF = 1000000005;
10 typedef long long LL;
11 int first[maxn];
12 int n,m;
13 int scnt,dfs_clock,ecnt;
14 int low[maxn],pre[maxn],sc[maxn];
15 int in[maxn];
16 int d[maxn];
17 stack<int> S;
18 
19 struct Edge{
20     int v,next,w;
21 }e[10*maxn];
22 
23 void init(){
24     ecnt = 0;
25     memset(first,-1,sizeof(first));
26     memset(in,0,sizeof(in));
27     for(int i = 1;i <= n;i++) d[i] = INF;
28 }
29 
30 void addedges(int u,int v,int w){
31     e[ecnt].v = v;
32     e[ecnt].w = w;
33     e[ecnt].next = first[u];
34     first[u] = ecnt++;
35 }
36 
37 void dfs(int u){
38     low[u] = pre[u] = ++dfs_clock;
39     S.push(u);
40     for(int i = first[u];~i;i = e[i].next){
41         int v = e[i].v;
42         if(!pre[v]){
43             dfs(v);
44             low[u] = min(low[u],low[v]);
45         }
46         else if(!sc[v]) low[u] = min(low[u],pre[v]);
47     }
48     if(pre[u] == low[u]){
49         scnt++;
50         for(;;){
51             int x = S.top();S.pop();
52             sc[x] = scnt;
53             if(x == u) break;
54         }
55     }
56 }
57 
58 void find_scc(){
59     scnt = dfs_clock = 0;
60     memset(low,0,sizeof(low));memset(pre,0,sizeof(pre));
61     memset(sc,0,sizeof(sc));
62     
63     for(int i = 1;i <= n;i++) if(!pre[i]) dfs(i);
64 }
65 
66 int main(){
67     while(scanf("%d %d",&n,&m) != EOF){
68         init();
69         for(int i = 0;i < m;i++){
70             int u,v,w;
71             scanf("%d %d %d",&u,&v,&w);u++;v++;
72             addedges(u,v,w);
73         }
74         find_scc();
75         for(int u = 1;u <= n;u++){
76             for(int i = first[u];~i;i = e[i].next){
77                 int v = e[i].v;
78                 if(sc[u] != sc[v]) d[sc[v]] = min(d[sc[v]],e[i].w);
79             }
80         }
81         
82         LL ans = 0;
83         for(int i = 1;i <= scnt;i++) {
84             if(d[i] != INF) ans += d[i];
85         }
86         printf("%I64d\n",ans);
87     }
88     return 0;
89 }
View Code

 poj 3114

缩点之后,存边的时候可以贪心,维持两个连通分量间的最小距离,
再用dijkstra,

最开始看到n是500,兴高采烈地用floyd---t掉了----

too--young--

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<iostream>
  4 #include<algorithm>
  5 #include<vector>
  6 #include<stack>
  7 using namespace std;
  8 
  9 const int maxn = 505;
 10 const int INF = 1000000005;
 11 int n,m,q;
 12 int first[maxn],first1[maxn];
 13 int low[maxn],pre[maxn],sc[maxn];
 14 int ecnt,ecnt1,dfs_clock,scnt;
 15 stack<int> S;
 16 
 17 int d[maxn][maxn];
 18 int vis[maxn];
 19 int dis[maxn];
 20 
 21 struct Edge{
 22     int v,next,w;
 23 };
 24 
 25 Edge e[maxn*maxn],e1[maxn*maxn];
 26 
 27 void init(){
 28     ecnt = ecnt1 = 0;
 29     memset(first,-1,sizeof(first));
 30 }
 31 
 32 void dijkstra(int s,int N){
 33     for(int i=1;i<=N;i++) dis[i]=INF,vis[i] = 0;
 34     dis[s]=0;
 35     
 36     for(int k=1;k<=N;k++){
 37         int p,m=INF;
 38         for(int i=1;i<=N;i++) if(!vis[i]&&dis[i]<m) m=dis[p=i];
 39         vis[p]=1;
 40         for(int i=1;i<=N;i++) dis[i]=min(dis[i],dis[p]+d[p][i]);
 41     }
 42 }
 43 
 44 void addedges(int u,int v,int w){
 45     e[ecnt].v = v;
 46     e[ecnt].w = w;
 47     e[ecnt].next = first[u];
 48     first[u] = ecnt++;
 49 }
 50 
 51 void tarjan(int u,int fa){
 52     low[u] = pre[u] = ++dfs_clock;
 53     S.push(u);
 54     for(int i = first[u];~i;i = e[i].next){
 55         int v = e[i].v;
 56         if(!pre[v]){
 57             tarjan(v,u);
 58             low[u] = min(low[u],low[v]);
 59         }
 60         else if(!sc[v]) low[u] = min(low[u],pre[v]);
 61     }
 62     if(low[u] == pre[u]){
 63         scnt++;
 64         for(;;){
 65             int x = S.top();S.pop();
 66             sc[x] = scnt;
 67             if(x == u) break;
 68         }
 69     }
 70 }
 71 
 72 void find_scc(){
 73     scnt = dfs_clock = 0;
 74     memset(low,0,sizeof(low));memset(pre,0,sizeof(pre));
 75     memset(sc,0,sizeof(sc));
 76     while(!S.empty()) S.pop();
 77     
 78     for(int i = 1;i <= n;i++) if(!pre[i]) tarjan(i,-1);
 79 }
 80 
 81 
 82 int main(){
 83     int kase = 0;
 84     while(scanf("%d %d",&n,&m) != EOF && n){
 85         if(kase) puts("");kase++;
 86         init();
 87         for(int i = 1;i <= m;i++){
 88             int u,v,w;
 89             scanf("%d %d %d",&u,&v,&w);
 90             addedges(u,v,w);
 91         }
 92         
 93         
 94         find_scc();
 95         //扫一遍边,边的两端在同一个连通分量的,权值设为0;
 96         
 97         for(int i =1 ;i <= scnt;i++){
 98             for(int j = 1;j <= scnt;j++){
 99                 if(i != j) d[i][j] = INF;
100                 else d[i][j] = 0;
101             }
102         }
103         
104         for(int u = 1;u <= n;u++){
105             for(int i = first[u];~i;i = e[i].next){
106                 int v = e[i].v;
107                 if(sc[u] != sc[v]) d[sc[u]][sc[v]] = min(d[sc[u]][sc[v]],e[i].w);
108                 else d[sc[u]][sc[v]] = 0;
109             }
110         }
111           
112         scanf("%d",&q);
113         while(q--){
114             int u,v;
115             scanf("%d %d",&u,&v);
116             if(sc[u] == sc[v]) puts("0");
117             else{
118                 dijkstra(sc[u],scnt);
119                 if(dis[sc[v]] == INF) printf("Nao e possivel entregar a carta\n");
120                 else printf("%d\n",dis[sc[v]]);
121             }
122         }
123     }
124     return 0;
125 }
View Code

 

poj 2253

如果一个点能够到达的其他的点也能够到达它,则把它叫做一个底,求图里面的所有的底

缩点,统计出度为0的块,块里面的所有的点都满足

话说数组开成5005为什么会t啊----开大点就过了----

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<stack>
 6 using namespace std;
 7 
 8 const int maxn = 20005;
 9 int n,m;
10 int first[maxn];
11 int low[maxn],pre[maxn],sc[maxn];
12 int dout[maxn];
13 int scnt,ecnt,dfs_clock;
14 int c[maxn];
15 stack<int> S;
16 
17 struct Edge{
18     int v,next;
19 }e[10*maxn];
20 
21 void init(){
22     ecnt = 0;
23     memset(first,-1,sizeof(first));
24     memset(dout,0,sizeof(dout));
25 }
26 
27 void addedges(int u,int v){
28     e[ecnt].v = v;
29     e[ecnt].next = first[u];
30     first[u] = ecnt++;
31 }
32 
33 void tarjan(int u,int fa){
34     low[u] = pre[u] = ++dfs_clock;
35     S.push(u);
36     for(int i = first[u];~i;i = e[i].next){
37         int v = e[i].v;
38         if(!pre[v]){
39             tarjan(v,u);
40             low[u] = min(low[u],low[v]);
41         }
42         else if(!sc[v]) low[u] = min(low[u],pre[v]);
43     }
44     if(pre[u] == low[u]){
45         scnt++;
46         for(;;){
47             int x = S.top();S.pop();
48             sc[x] = scnt;
49             if(x == u) break;
50         }
51     }
52 }
53 
54 void find_scc(){
55     while(!S.empty()) S.pop();
56     dfs_clock = ecnt = 0;
57     memset(low,0,sizeof(low));memset(pre,0,sizeof(pre));
58     memset(sc,0,sizeof(sc));
59     for(int i = 1;i <= n;i++) if(!pre[i]) tarjan(i,-1);
60 }
61 
62 int main(){
63     while(scanf("%d",&n) != EOF && n){
64         scanf("%d",&m);
65         init();
66         for(int i = 1;i <= m;i++){
67             int u,v;
68             scanf("%d %d",&u,&v); addedges(u,v);
69         }
70         find_scc();
71         for(int u = 1;u <= n;u++){
72             for(int i = first[u];~i;i = e[i].next){
73                 int v = e[i].v;
74                 if(sc[u] != sc[v]) dout[sc[u]]++;
75             }
76         }
77         int num = 0;
78         for(int i = 1;i <= n;i++){
79             if(dout[sc[i]] == 0) printf("%d ",i);
80         }
81         printf("\n");
82     }
83     return 0; 
84 }
View Code

 

poj 2186

求出这样的点的个数,即其他点都能够到达它的点

先缩点,缩完点之后是一个DAG,DAG的终点(出度为0的点)就是要求的,

如果终点有多个,则不满足了,因为缩点之后不存在环,所以终点之间的点不能到达

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<stack>
 6 using namespace std;
 7 
 8 const int maxn = 20005;
 9 int first[maxn];
10 int low[maxn],pre[maxn],sc[maxn];
11 int din[maxn],dout[maxn];
12 int n,m;
13 int ecnt,scnt,dfs_clock;
14 stack<int> S;
15 
16 struct Edge{
17     int v,next;
18 }e[3*maxn];
19 
20 void init(){
21     ecnt = 0;
22     memset(first,-1,sizeof(first));
23     memset(din,0,sizeof(din));
24     memset(dout,0,sizeof(dout));
25 }
26 
27 void addedges(int u,int v){
28     e[ecnt].v = v;
29     e[ecnt].next = first[u];
30     first[u] = ecnt++;
31 }
32 
33 void dfs(int u){
34     low[u] = pre[u] = ++dfs_clock;
35     S.push(u);
36     for(int i = first[u];~i;i = e[i].next){
37         int v = e[i].v;
38         if(!pre[v]){
39             dfs(v);
40             low[u] = min(low[u],low[v]);
41         }
42         else if(!sc[v]) low[u] = min(low[u],pre[v]);
43     }
44     if(pre[u] == low[u]){
45         scnt++;
46         for(;;){
47             int x = S.top();S.pop();
48             sc[x] = scnt;
49             if(x == u) break;
50         }
51     }
52 }
53 
54 void find_scc(){
55     while(!S.empty()) S.pop();
56     memset(low,0,sizeof(low));memset(pre,0,sizeof(pre));
57     memset(sc,0,sizeof(sc));
58     dfs_clock = scnt = 0;
59     for(int i = 1;i <= n;i++) if(!pre[i]) dfs(i);
60 }
61 
62 int main(){
63     while( scanf("%d %d",&n,&m) != EOF){
64         init();
65         for(int i = 1;i <= m;i++){
66             int u,v;
67             scanf("%d %d",&u,&v);
68             addedges(u,v);
69         }
70         find_scc();
71         for(int u = 1;u <= n;u++){
72             for(int i = first[u];~i;i = e[i].next){
73                 int v = e[i].v;
74                 if(sc[u] != sc[v]){
75                     dout[sc[u]]++;
76                 }
77             }
78         }
79         int c = 0;
80         for(int i = 1;i <= scnt;i++){
81             if(dout[i] == 0) c++;
82         }
83         if(c > 1) printf("0\n");
84         else{
85             int res = 0;
86             for(int i = 1;i <= n;i++){
87                 if(dout[sc[i]] == 0) res++;
88             }
89             printf("%d\n",res);
90         }
91     }
92     return 0;
93 }
View Code

 

转载于:https://www.cnblogs.com/wuyuewoniu/p/4688309.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值