九度oj 1418 题目1418:宝藏

本文介绍了一种利用Tarjan算法寻找图中的强连通分量的方法,并通过一个具体的C++实现示例展示了算法的工作流程。该算法首先通过深度优先搜索(DFS)为每个顶点分配访问序号,并使用栈来保存当前搜索路径上的所有顶点。

http://ac.jobdu.com/problem.php?id=1418  强连通分量tarjan+dfs

View Code
  1 #include<iostream>
2 #include<vector>
3 #include<cstdio>
4 #include<cmath>
5 #include<stack>
6 #include<cstring>
7 using namespace std;
8 const int N=100008;
9 vector<int>mat[N];//原图
10 vector<int>mat2[N];//
11 int set[N];//i属于哪个连通分量的标记,set[i]
12 int num[N];//每个连通分量里面点的个数
13
14 bool visited[N];//某个点是否访问过
15 bool instack[N];//某个点是否在栈中
16 int dfn[N];//存放节点访问顺序
17 int low[N]; //具体看百度
18 stack<int>stk;//
19 int seq=0;//求连通分量是,节点访问顺序
20 int cnt=0;//连通分量个数
21 int n;//节点个数
22 void init()
23 {
24 for(int i=0;i<=n;i++) mat[i].clear();
25 for(int i=0;i<=n;i++) mat2[i].clear();
26 memset(num,0,sizeof(num));
27 memset(visited,false,sizeof(visited));
28 memset(instack,false,sizeof(instack));
29 while(!stk.empty()) stk.pop();
30 seq=0;
31 cnt=0;
32 }
33 void tarjan(int cur)//从cur开始求连通分量 ,具体算法看百度
34 {
35 dfn[cur]=low[cur]=++seq;
36 visited[cur]=true;
37 stk.push(cur);
38 instack[cur]=true;
39 int i;
40 for(i=0;i<mat[cur].size();i++)
41 {
42 int x=mat[cur][i];//cur的邻接点
43 if(!visited[x])//没有被访问过
44 {
45 tarjan(x);
46 low[cur]=min(low[cur],low[x]);
47 }
48 else if(instack[x])
49 {
50 low[cur]=min(low[cur],dfn[x]);
51 }
52 }
53 if(low[cur]==dfn[cur])
54 {
55 cnt++;
56 while(true)
57 {
58 int temp=stk.top();
59 stk.pop();
60 instack[temp]=false;
61 set[temp]=cnt;
62 num[cnt]++;
63 if(temp==cur) break;
64 }
65 }
66 }
67 void build()//把一个连通分量作为一个点,建立另一个图
68 {
69 int i,j,x;
70 for(i=1;i<=n;i++)
71 {
72 for(j=0;j<mat[i].size();j++)
73 {
74 x=mat[i][j];
75 //i和其邻接点不属于一个连通分量
76 if(set[i]!=set[x]) mat2[set[i]].push_back(set[x]);
77 }
78 }
79 }
80 void print()
81 {
82 int i,j;
83 for(i=1;i<=n;i++) cout<<"set("<<i<<")="<<set[i]<<endl;
84 for(i=1;i<=cnt;i++) cout<<"num["<<i<<"]="<<num[i]<<endl;
85 for(i=1;i<=cnt;i++)
86 {
87 cout<<i<<":";
88 for(j=0;j<mat2[i].size();j++)
89 cout<<mat2[i][j]<<" ";
90 cout<<endl;
91 }
92 }
93 int dfs(int cur)//根据新建的图mat2,找最大值
94 {
95 int i, maxx=0,adj,temp;
96 visited[cur]=true;
97 for(i=0;i<mat2[cur].size();i++)
98 {
99 adj=mat2[cur][i];
100 if(!visited[adj])
101 {
102 temp=dfs(adj);
103 if(temp>maxx) maxx=temp;
104 visited[adj]=false;
105 }
106 }
107 //cout<<"cur:"<<cur<<endl;
108 //cout<<"max+num[cur]:"<<maxx<<"+"<<num[cur]<<"="<<maxx+num[cur]<<endl;
109 return maxx+num[cur];
110 }
111 int main()
112 {
113 int t=0,m,s;
114 while(scanf("%d%d%d",&n,&m,&s)==3)
115 {
116 init();
117 int i,j,x,y;
118 for(i=1;i<=m;i++)
119 {
120 scanf("%d%d",&x,&y);
121 mat[x].push_back(y);
122 }
123 for(i=1;i<=n;i++)
124 if(!visited[i]) tarjan(i);
125 //cout<<"cnt:"<<cnt<<endl;
126 build();
127 //print();
128 memset(visited,false,sizeof(visited));
129 printf("Case %d:\n%d\n",++t,dfs(set[s])); //从s所属的强连通分量开始
130 }
131 return 0;
132 }


 

  1 #include<iostream>
2 #include<vector>
3 #include<cstdio>
4 #include<cmath>
5 #include<stack>
6 #include<cstring>
7 using namespace std;
8 const int N=100008;
9 vector<int>mat[N];//原图
10 vector<int>mat2[N];//
11 int set[N];//i属于哪个连通分量的标记,set[i]
12 int num[N];//每个连通分量里面点的个数
13
14 bool visited[N];//某个点是否访问过
15 bool instack[N];//某个点是否在栈中
16 int dfn[N];//存放节点访问顺序
17 int low[N]; //具体看百度
18 stack<int>stk;//
19 int seq=0;//求连通分量是,节点访问顺序
20 int cnt=0;//连通分量个数
21 int n;//节点个数
22 void init()
23 {
24 for(int i=0;i<=n;i++) mat[i].clear();
25 for(int i=0;i<=n;i++) mat2[i].clear();
26 memset(num,0,sizeof(num));
27 memset(visited,false,sizeof(visited));
28 memset(instack,false,sizeof(instack));
29 while(!stk.empty()) stk.pop();
30 seq=0;
31 cnt=0;
32 }
33 void tarjan(int cur)//从cur开始求连通分量 ,具体算法看百度
34 {
35 dfn[cur]=low[cur]=++seq;
36 visited[cur]=true;
37 stk.push(cur);
38 instack[cur]=true;
39 int i;
40 for(i=0;i<mat[cur].size();i++)
41 {
42 int x=mat[cur][i];//cur的邻接点
43 if(!visited[x])//没有被访问过
44 {
45 tarjan(x);
46 low[cur]=min(low[cur],low[x]);
47 }
48 else if(instack[x])
49 {
50 low[cur]=min(low[cur],dfn[x]);
51 }
52 }
53 if(low[cur]==dfn[cur])
54 {
55 cnt++;
56 while(true)
57 {
58 int temp=stk.top();
59 stk.pop();
60 instack[temp]=false;
61 set[temp]=cnt;
62 num[cnt]++;
63 if(temp==cur) break;
64 }
65 }
66 }
67 void build()//把一个连通分量作为一个点,建立另一个图
68 {
69 int i,j,x;
70 for(i=1;i<=n;i++)
71 {
72 for(j=0;j<mat[i].size();j++)
73 {
74 x=mat[i][j];
75 //i和其邻接点不属于一个连通分量
76 if(set[i]!=set[x]) mat2[set[i]].push_back(set[x]);
77 }
78 }
79 }
80 void print()
81 {
82 int i,j;
83 for(i=1;i<=n;i++) cout<<"set("<<i<<")="<<set[i]<<endl;
84 for(i=1;i<=cnt;i++) cout<<"num["<<i<<"]="<<num[i]<<endl;
85 for(i=1;i<=cnt;i++)
86 {
87 cout<<i<<":";
88 for(j=0;j<mat2[i].size();j++)
89 cout<<mat2[i][j]<<" ";
90 cout<<endl;
91 }
92 }
93 int dfs(int cur)
94 {
95 int i, maxx=0,adj,temp;
96 visited[cur]=true;
97 for(i=0;i<mat2[cur].size();i++)
98 {
99 adj=mat2[cur][i];
100 if(!visited[adj])
101 {
102 temp=dfs(adj);
103 if(temp>maxx) maxx=temp;
104 visited[adj]=false;
105 }
106 }
107 //cout<<"cur:"<<cur<<endl;
108 //cout<<"max+num[cur]:"<<maxx<<"+"<<num[cur]<<"="<<maxx+num[cur]<<endl;
109 return maxx+num[cur];
110 }
111 int main()
112 {
113 int t=0,m,s;
114 while(scanf("%d%d%d",&n,&m,&s)==3)
115 {
116 init();
117 int i,j,x,y;
118 for(i=1;i<=m;i++)
119 {
120 scanf("%d%d",&x,&y);
121 mat[x].push_back(y);
122 }
123 for(i=1;i<=n;i++)
124 if(!visited[i]) tarjan(i);
125 //cout<<"cnt:"<<cnt<<endl;
126 build();
127 //print();
128 memset(visited,false,sizeof(visited));
129 printf("Case %d:\n%d\n",++t,dfs(set[s])); //从s所属的强连通分量开始
130 }
131 return 0;
132 }


 

转载于:https://www.cnblogs.com/keepmoving89/archive/2012/04/04/2431978.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值