• 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 }

    这个算法曾经花了好久才学明白,都是一些细节没弄通,但是一步一步打草稿演算就慢慢弄懂了,收获很多。

  • 相关阅读:
    概率图模型导论
    超平面与法向量
    感知机
    最全的常用正则表达式大全——包括校验数字、字符、一些特殊的需求等等
    数组去重的几种方法
    Vuex学习笔记(-)安装vuex
    js判断一个字符串是否是回文字符串
    取出字符串中的所有数字
    js将手机号中间四位变成*号
    微信小程序电商实战(-)商城首页
  • 原文地址:https://www.cnblogs.com/wwq-19990526/p/8987756.html
Copyright © 2020-2023  润新知