強連通------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 強連通、點雙、邊雙及其縮點 重磅來襲!!!!演算法
- kosaraju 和 tarjan演算法詳解(強連通分量)演算法
- 連通圖與Tarjan演算法演算法
- Tarjan演算法_縮點演算法
- 連通圖演算法詳解之① :Tarjan 和 Kosaraju 演算法演算法
- tarjan演算法求scc & 縮點演算法
- 強連通分量及縮點 演算法解析及例題演算法
- 強連通分量(Tarjan演算法)演算法
- 強聯通分量及縮點法
- Tarjan演算法(強連通分量分解)演算法
- 圖論——強連通分量(Tarjan演算法)圖論演算法
- Tarjan縮點題單 刷題題解
- 強聯通分量tarjan
- Tarjan求強連通分量
- UVA1327 && POJ1904 King's Quest(tarjan+巧妙建圖+強連通分量+縮點)
- 【Tarjan SCC 加邊使得所有圖聯通 至少選取多少個點能圖聯通 】Network of Schools加強版.md
- Tarjan演算法及其應用 總結+詳細講解+詳細程式碼註釋演算法
- Proxy詳解,運用與Mobx
- 尋找圖的強連通分量:tarjan演算法簡單理解演算法
- 強強聯手!國際電子競技聯合會與英聯邦運動會聯合會達成合作
- tarjan縮點-受歡迎的牛-筆記筆記
- 20行程式碼實現,使用Tarjan演算法求解強連通分量行程演算法
- POJ2533&&SP1799 The Bottom of a Graph(tarjan+縮點)
- 【Tarjan 拓撲排序 dp】P3387 【模板】縮點排序
- Tarjan 求有向圖的強連通分量
- 模型壓縮-剪枝演算法詳解模型演算法
- Linux 常用的壓縮與解壓縮命令詳解Linux
- websocket 運用詳解Web
- KMP演算法超詳解與其應用KMP演算法
- 硬連結與軟連結詳解
- AIIA聯合信通院:MLOps實踐DataExa-Insight中臺及應用AI
- NeurIPS 2018 | 騰訊AI Lab詳解3大熱點:模型壓縮、機器學習及最優化演算法AI模型機器學習優化演算法
- C#自增運算子詳解:++i與i++的區別及應用場景C#
- LTR那點事—AUC及其與線上點選率的關聯詳解
- 強化學習詳解:理論基礎與核心演算法解析強化學習演算法
- Linux常用命令之檔案壓縮與解壓縮命令詳解Linux
- LCA(倍增與Tarjan)