【图论】tarjan

刚接触tarjan,tarjan其实更多是用来找强联通分量。我这里呢,是看qsc的视频学的。卿学姐讲的其实很清楚啦。

我这里只是做个整理。

 

low[]:表示能到达这个点的最小编号。[树枝边]。啊,其实我觉得就是保存环路的起点。QWQ。因为只要记录了这个点,栈中经历的点都能到达嘛都是强联通啊。

dfn[]:搜索到这个点的时间是多少。[后叉边]。时间戳。

vis[]:该点是否进栈。

 

伪代码如下:

 1 tarjan(x)
 2 low[x] = dfn[x] = ++index;
 3 stack.push(x);
 4 vis[x] = 1;//表示在栈中。
 5 for(v属于E){
 6     if(vis[v] == 0)
 7         tarjan(v),low[x] = min(low[x],low[v]);
 8     if(vis[v]){
 9         low[x] = min(low[x],dfn[v]);
10     }
11 } 
12 
13 if(low[x] == dfn[x]){    //这里其实就是表示点已经通过某一种方式到达了自己 
14     做出栈操作 
15 } 

 

这里主要就是在两个if中要理解。

如果该点没有进栈,当前存的当然要是最短的。

如果该点进栈了,就去看他的dfn[]存的是什么,就更新。

 

具体的举例请看卿学姐的视频啊。QWQ。。有时间我补图上来。。

 

例题题目链接:NOIP2015信息传递

代码:

#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
using namespace std;
const int maxn = 2e5+7;

vector<int> E[maxn];
int dfn[maxn],low[maxn],tot = 0,n,ans = maxn;
stack<int> S;
int vis[maxn];

void tarjan(int x){
    low[x] = dfn[x] = tot++;
    S.push(x);
    vis[x] = 1;
    for(int i = 0 ; i < E[x].size() ;i++){
        int v = E[x][i];
        if(!dfn[v]){
            tarjan(v);
            low[x] = min(low[x],low[v]);
         } 
         else if(vis[v]){
             low[x] = min(low[x],dfn[v]);
             
        }
    }
    if(low[x] == dfn[x]){
        int cnt = 0;
        while(1){
            int now = S.top();
            S.pop();
            vis[x] = 0;
            cnt++;
            if(now == x){
                break;
            }
        }
        if(cnt > 1 )
            ans = min(ans,cnt);
    }
}


int main(){
    cin>>n;
    for(int i = 1; i <= n ;i++){
        int x;
        cin>>x;
        E[i].push_back(x);
    }
    for(int i = 1; i <= n ;i++){
        if(!dfn[i]){
            tarjan(i);
        }
    }
    
    cout<<ans<<endl; 
    
    return 0;
} 

 

posted @ 2018-05-20 21:28  甜酒果。  阅读(179)  评论(0编辑  收藏  举报