強連通------tarjan演算法詳解及與縮點聯合運用
什麼是tarjan演算法?(如何求強連通)
1.首先定義兩個陣列dfn和low,
dfn[x]表示x節點是第幾個被遍歷到的。
low[x]表示包含x在內的強連通分量的dfn的最小值。(也就是說這個強連通分量中最早被遍歷到的)
2,我們用一個棧stack來儲存遍歷到的點,再定義一個陣列vis[],把當前搜到的點的入棧標記為vis[x]=1。
3,對於每一個當前節點的子節點,如果之前沒有遍歷到,就往下遍歷,並在遍歷後取low的min值:low[x]=min(low[x],low[v])。如果之前已經遍歷到,且是棧中元素(vis[v]=1),那麼我們就不再往下繼續搜了,直接傳遞dfn的值:low[x]=min(low[x],dfn[v]);
4,如果當前節點的dfn的值等於low的值,由於low表示包含當前節點的強連通分量的最小dfn的值,那麼我們就可以認為low被傳遞了一圈又回到了當前dfn,也就代表找到了一個強聯通分量,那麼我們就把從當前的棧頂一直到當前元素的棧中元素全部彈出並作為強聯通分量的一部分。
void tarjan(int X)
{
vis[X]=1;
dfn[X]=low[X]=++cnt;
sta.push(X);
for(int i=0;i<vec[X].size();i++)
{
int to=vec[X][i];
if(!dfn[to])
{
tarjan(to);
low[X]=min(low[X],low[to]);
}
else if(vis[to])
low[X]=min(low[X],dfn[to]);
}
if(low[X]==dfn[X])
{
flag++;//計算有多少個強連通分量
while(sta.top()!=X)
{
vis[sta.top()]=0;
sta.pop();
}
vis[sta.top()]=0;
sta.pop();//把x本身出棧
}
}
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e4+2;
int n,m,dfn[maxn],low[maxn],flag,vis[maxn],cnt;
vector<int> vec[maxn];
stack<int> sta;
void tarjan(int X)
{
vis[X]=1;
dfn[X]=low[X]=++cnt;
sta.push(X);
for(int i=0;i<vec[X].size();i++)
{
int to=vec[X][i];
if(!dfn[to])
{
tarjan(to);
low[X]=min(low[X],low[to]);
}
else if(vis[to])
low[X]=min(low[X],dfn[to]);
}
if(low[X]==dfn[X])
{
flag++;
while(sta.top()!=X)
{
vis[sta.top()]=0;
sta.pop();
}
vis[sta.top()]=0;
sta.pop();
}
}
int main()
{
int n,m;
while(cin>>n>>m) {
if(n==m&&n==0)
break;
for(int i=1;i<=n;i++)
vec[i].clear();
for(int i=0;i<m;i++)
{
int x,y;
cin>>x>>y;
vec[x].push_back(y);
}
flag=0;
cnt=0;//cout<<"1";
memset(low,0,sizeof(low));
memset(dfn,0,sizeof(dfn));
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
{
if(!dfn[i])
tarjan(i);
}
if(flag==1)
cout<<"Yes"<<endl;
else
cout<<"No"<<endl;}
return 0;
}
與縮點結合運用
最小點基演算法(縮點):
是強連通的一個應用,找出圖G的所有強連通分量,將每個強連通分量各自縮成一個點v,即刪除各個強連通分量內的邊,連線v與原強連通分量相連線的點。縮點後再找出入度為0的點,就是縮點前的最高的強連通分量。最小點基就從最高的強連通分量中任選一個頂點,組成的頂點集B就是圖G的一個最小點基。
最小權點基(縮權):
最小權點基的演算法基本上根最小點基一樣,最小點基最後是從最高的強連通分量中任選一個頂點,組成最小點基;而最小權點基則是從最高的強連通分量中取權值最小的頂點,組成最小權點基。
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
#include<stack>
using namespace std;
const int maxn=1e3+3;
int N,M,summ,flag,n_val[maxn],low[maxn],dfn[maxn],vis[maxn],cnt,tar[maxn],ru[maxn],mincost[maxn];
vector<int> mapp[maxn];
stack<int> sta;
void tarjan(int x)
{
vis[x]=1;
dfn[x]=low[x]=++cnt;
sta.push(x);
for(int i=0;i<mapp[x].size();i++)
{
int to=mapp[x][i];
if(!dfn[to])
{
tarjan(to);
low[x]=min(low[x],low[to]);
}
else if(vis[to])
low[x]=min(low[x],dfn[to]);
}
if(dfn[x]==low[x])
{
flag++;
while(sta.top()!=x)
{
vis[sta.top()]=0;
tar[sta.top()]=flag;//tar陣列就是中x表示強連通中的點,tar【x】表示這個強連通是第幾個(給強連通命名排序了),把每個強連通都變成一個點
sta.pop();
}
vis[sta.top()]=0;
tar[sta.top()]=flag;
sta.pop();
}
}
int main()
{
while(~scanf("%d%d",&N,&M))
{
for(int i=0;i<=N;i++)
mapp[i].clear();
memset(tar,0,sizeof(tar));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(vis,0,sizeof(vis));
memset(ru,0,sizeof(ru));
for(int i=1;i<=N;i++)
{
scanf("%d",&n_val[i]);
}
while(M--)
{
int x,y;
scanf("%d%d",&x,&y);
mapp[x].push_back(y);
}
cnt=0;
summ=0;
flag=0;
for(int i=1;i<=N;i++)
if(!dfn[i])
tarjan(i);
for(int i=1;i<=N;i++)
{
for(int j=0;j<mapp[i].size();j++)
{
int to=mapp[i][j];
if(tar[i]!=tar[to])//如果兩個不是一個強連通分量,但i可以到to
ru[tar[to]]=1;//標記這個點可通到(如果ru【x】為零,代表x為最高的強連通分量)
}
}
for(int i=1;i<=N;i++)
mincost[i]=1000000000;
for(int i=1;i<=N;i++)
{
if(mincost[tar[i]]>n_val[i]&&ru[tar[i]]==0)//權值比較,找出最高的強連通分量的最小權值
mincost[tar[i]]=n_val[i];
}
int num=0;
for(int i=1;i<=flag;i++)
{
if(ru[i]==0)//從強連通分量中找最高的強連通分量
{
num++;
summ+=mincost[i];
}
}
printf("%d %d\n",num,summ);}
return 0;
}
相關文章
- 強連通分量及縮點tarjan演算法解析演算法
- 強連通演算法--Tarjan個人理解+詳解演算法
- HDU 2767 Proving Equivalences Tarjan 強連通縮點UI
- 【模板】tarjan 強連通分量縮點
- 【演算法學習】tarjan 強連通、點雙、邊雙及其縮點 重磅來襲!!!!演算法
- 強連通分量-tarjan演算法模板詳解演算法
- 強連通分量與縮點(Tarjan演算法)(洛谷P3387)演算法
- Trajan演算法(強連通+縮點)演算法
- 圖之強連通、強連通圖、強連通分量 Tarjan演算法演算法
- kosaraju 和 tarjan演算法詳解(強連通分量)演算法
- POJ 2186 Popular Cows(強連通分量縮點,Tarjan演算法)演算法
- 連通圖與Tarjan演算法演算法
- 圖論複習之強連通分量以及縮點—Tarjan演算法圖論演算法
- Tarjan演算法_縮點演算法
- 連通圖演算法詳解之① :Tarjan 和 Kosaraju 演算法演算法
- 強連通分量及縮點 演算法解析及例題演算法
- tarjan演算法求scc & 縮點演算法
- 強連通分量(Tarjan演算法)演算法
- Tarjan演算法(強連通分量分解)演算法
- 圖論——強連通分量(Tarjan演算法)圖論演算法
- Tarjan縮點題單 刷題題解
- Tarjan演算法求強連通分量總結演算法
- 演算法學習之路|強連通分量+縮點演算法
- Tarjan演算法三大應用之強連通分量演算法
- 【Tarjan SCC 加邊使得所有圖聯通 至少選取多少個點能圖聯通 】Network of Schools加強版.md
- 全網最!詳!細!Tarjan演算法講解。演算法
- 尋找圖的強連通分量:tarjan演算法簡單理解演算法
- Proxy詳解,運用與Mobx
- Tarjan演算法及其應用 總結+詳細講解+詳細程式碼註釋演算法
- 強連通圖的演算法演算法
- 20行程式碼實現,使用Tarjan演算法求解強連通分量行程演算法
- tarjan縮點-受歡迎的牛-筆記筆記
- Tarjan 求有向圖的強連通分量
- ZIP壓縮演算法詳細分析及解壓例項解釋演算法
- 【Tarjan 拓撲排序 dp】P3387 【模板】縮點排序
- 模型壓縮-剪枝演算法詳解模型演算法
- HDU2767Proving Equivalences[強連通分量 縮點]UI
- websocket 運用詳解Web