1. 程式人生 > 其它 >JavaScript簡介

JavaScript簡介

Tarjan

作用:

  1. 求強連通分量(求環)
  2. 求割點(同上)
  3. 縮點,將有向圖變成有向無環圖(進行topsort)

實現:

void tarjan(int x){
    low[x]=dfn[x]=++cnt;
    sta[++top]=x;//在棧中,表示在同一個強連通分量
    vis[x]=1;
    for(int i=head[x];i;i=nxt[i]){
        int y=ver[i]; 
        if(!dfn[y]){
            tarjan(y); low[x]=min(low[x],low[y]);
        }
        else if(vis[y]) low[x]=min(low[x],dfn[y]);//搜尋到的最小棧中節點dfs序
    }
    if(dfn[x]==low[x]){
        int y; 
        while(y=sta[top--]){//縮點
            sd[y]=x; vis[y]=0; if(x==y) break;
            val[x]+=val[y];
        }
    }
}

其中,\(dfn[x]\)\(x\)\(dfs\) 序,而 \(low[x]\) 為在該強連通分量中所能找到的最小的 \(dfs\) 序的值。

如果 \(dfn[x]==low[x]\) ,那麼這個點就是割點,此時棧中從 \(sta[top] ——> x\) 就是這個強連通分量的點。

又因為加入棧的順序是按邊加入的,所以我們也能記錄強連通分量的邊,從而得到圖中的環。

我們在縮點之後整個圖就變成 \(DAG\) ,就能進行拓撲或者算權值等操作。

例題:
P3387 【模板】縮點
這題是模板題。

我們首先需要把所有點都縮成一個點,然後進行 \(dp\)

我們怎麼進行 \(dp\)

呢,因為我們縮完點之後形成了一個有向無環圖,我們可以進行拓撲排序,求出來 \(dp\) 的順序,然後增加值就行。

程式碼:

//P3387 【模板】縮點
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,m,val[N],top;
int nxt[N],ver[N],tot,head[N],from[N];
int dfn[N],low[N],cnt;
int sta[N],vis[N];//棧表示此時是否有父子關係
int sd[N];//把環上所有點都彙總到一個點
int deg[N],dis[N];
struct node{
    int nxt,ver,edge,head,from;
}t[N]; 
void add(int x,int y){
    ver[++tot]=y;from[tot]=x;nxt[tot]=head[x];head[x]=tot;
}
void tarjan(int x){
    low[x]=dfn[x]=++cnt;
    sta[++top]=x;//在棧中,表示在同一個強連通分量
    vis[x]=1;
    for(int i=head[x];i;i=nxt[i]){
        int y=ver[i]; 
        if(!dfn[y]){
            tarjan(y); low[x]=min(low[x],low[y]);
        }
        else if(vis[y]) low[x]=min(low[x],dfn[y]);//搜尋到的最小棧中節點dfs序
    }
    if(dfn[x]==low[x]){
        int y; 
        while(y=sta[top--]){//縮點
            sd[y]=x; vis[y]=0; if(x==y) break;
            val[x]+=val[y];
        }
    }
}
int tot1=0;
void add1(int x,int y,int z){
    t[++tot1].ver=y; t[tot1].nxt=t[x].head; 
    t[tot1].edge=z; t[x].head=tot1; 
    deg[y]++; 
}
void topsort(){
    queue<int> q;
    for(int i=1;i<=n;i++) if(sd[i]==i&&!deg[i]){
        q.push(i); dis[i]=val[i];
    }
    while(!q.empty()){
        int x=q.front() ; q.pop();
        for(int i=t[x].head;i;i=t[i].nxt){
            int y=t[i].ver; 
            dis[y]=max(dis[y],dis[x]+val[y]); 
            deg[y]--;
            if(deg[y]==0) q.push(y);
        }
    }
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++) scanf("%d",&val[i]);
    for(int i=1,x,y;i<=m;i++){
        scanf("%d%d",&x,&y); add(x,y);
    } 
    for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); 
    for(int i=1;i<=m;i++){
        int x=sd[from[i]],y=sd[ver[i]]; //沒有縮成一個點
       
        if(x!=y) add1(x,y,val[x]); 
    }
    topsort(); int ans=0;
    for(int i=1;i<=n;i++) ans=max(ans,dis[i]);
    cout<<ans<<endl;
    system("pause");
    return 0;
}