码迷,mamicode.com
首页 > 其他好文 > 详细

强连通

时间:2016-04-13 00:13:46      阅读:176      评论:0      收藏:0      [点我收藏+]

标签:

一、模板

(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

 

强连通

标签:

原文地址:http://www.cnblogs.com/yscc/p/5385030.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!