HDU 1269 Tarjan算法运用

强连通的点(即两点之间有路径可以相互到达),这道迷宫城堡题便是计算有几个强连通分量。

先说Tarjan,他的主体部分便是:

 1 void tarjan(int a)
 2 {
 3     checklow[a]=low[a]=++timer;
 4     visit[a]=1;
 5     for(int i=0;i<vec[a].size();i++)
 6     {
 7         int x=vec[a][i];
 8         if(visit[x]==0)    tarjan(x);
 9         if(visit[x]==1)    low[a]=min(low[a],low[x]); 
10     }
11 }

原理如下:checklow用于储存low未改变之前的值,low值在递归时可能会被更新,timer代表点a的权值,x代表下一个点,visit[i]表示有没有被访问;

举个例子:有(1,2),(2,3),(3,4),(4,1)四组数据,tarjan(1)时,点1的权值为1,点1被标记访问,因为2未访问,故tarjan(2),点2权值为2且被标记访问,一直递归至点4后(此时:checklow[1]=low[1]=1,checklow[2]=low[2]=2,checklow[3]=low[3]=3,checklow[4]=low[4]=4);往1走,因为1被访问(即找到了可以形成圈的点了),故low[4]被更新为min(low[1],low[4])=1;然后返回到low[3]=min(low[3],low[4])=1;一直更新到low[1]=low[2]=1;所以点1,2,3,4全部成了满足条件权值为1的点了(4个点中现在只有1的checklow=low了,而且一个强连通分量有且只有一个点1);如果最后(4,1)改成(4,2),那么点2,3,4的权值为2,点1权值不变,因为退到点1递归时,low[1]=min(low[1],low[2])还是等于1,点2只会与点3(点3为点2的下一个点)作权值比较;Tarjan算法原理就是这个了,网上有很多大牛画图解释,讲的蛮好的;以下就是HDU 1269的解题代码:

 1 #include<iostream>
 2 #include<cstring>
 3 #include<vector>
 4 using namespace std;
 5 vector<int> vec[10005];//容器i代表第几个房间,值代表通向哪个房间; 
 6 int checklow[10005],low[10005],visit[10005],timer,count;
 7 int min(int a,int b)
 8 {
 9     return a>b?b:a; 
10 }
11 void tarjan(int a)
12 {
13     checklow[a]=low[a]=++timer;
14     visit[a]=1;
15     for(int i=0;i<vec[a].size();i++)
16     {
17         int x=vec[a][i];
18         if(visit[x]==0)    tarjan(x);
19         if(visit[x]==1)    low[a]=min(low[a],low[x]);//当前房间与下一个房间比较; 
20     }
21 }
22 int main()
23 {
24     int n,m;
25     while(cin>>n>>m&&n)
26     {
27         int a,b;
28         while(m--)
29         {
30             cin>>a>>b;
31             vec[a].push_back(b);//第几号房间存入连通房间 
32         }
33         memset(visit,0,sizeof(visit));
34         memset(checklow,0,sizeof(checklow));
35         memset(low,0,sizeof(low));
36         count=timer=0;
37         for(int i=1;i<=n;i++)//这样能把所有的房间遍历一遍; 
38         if(!visit[i]&&!vec[i].empty())
39             tarjan(i);
40         for(int i=1;i<=n;i++)
41         if(checklow[i]==low[i])
42         count++;//计算有多少组强连通分量 
43         if(count==1)//说明只有一组强连通分量,满足题意; 
44         cout<<"Yes"<<endl;
45         else
46         cout<<"No"<<endl;
47         for(int i=1;i<=n;i++)
48         vec[i].clear();//清空容器,不然上一组容器中存的数据会影响后面的判断; 
49     }
50     return 0;
51 }

这个算法曾经花了好久才学明白,都是一些细节没弄通,但是一步一步打草稿演算就慢慢弄懂了,收获很多,这可能是最后一篇博客园了,以后想去csdn写。

猜你喜欢

转载自www.cnblogs.com/wwq-19990526/p/8987756.html
今日推荐