圖論-有向圖縮點
強連通(strongly connected): 在一個有向圖G裡,設兩個點 a b 發現,由a有一條路可以走到b,由b又有一條路可以走到a,我們就叫這兩個頂點(a,b)強連通。
強連通圖: 如果 在一個有向圖G中,每兩個點都強連通,我們就叫這個圖,強連通圖。
強連通分量strongly connected components):在一個有向圖G中,有一個子圖,這個子圖每2個點都滿足強連通,我們就叫這個子圖叫做 強連通分量 。
有向圖的縮點就是把有向圖中強連通分量縮成一個點(道理很簡單,我到了這個強連通分量的任何一點,那麼這個強連通分量就能被我訪問了),在處理有向圖的連通性問題時有很多作用。
比如如下問題:
給出一個 0 ≤ N ≤ 105 點數、0 ≤ M ≤ 105 邊數的有向圖,
輸出一個儘可能小的點集,使得從這些點出發能夠到達任意一點,如果有多個這樣的集合,輸出這些集合升序排序後字典序最小的。
第一行為兩個整數 1 ≤ n, m ≤ 105,
接下來 M 行,每行兩個整數 1 ≤ u, v ≤ 105 表示從點 u 至點 v 有一條有向邊。
資料保證沒有重邊、自環。
第一行輸出一個整數 z,表示作為答案的點集的大小;
第二行輸出 z 個整數,升序排序,表示作為答案的點集。
7 10 4 5 5 1 2 5 6 5 7 2 4 2 1 2 5 3 3 5 3 6
2 4 7
不明白縮點的話,是很難做出來的,也有其他方法,這裡這是舉個例子來解決問題。
縮點其實難在求有向圖的強連通分量上面,這個得先去了解一下點選開啟連結
我們把輸出的程式碼改一下,記錄到一個陣列裡面並且同時給每一個點打上標記,即這些點都是一個強連通分量裡面的
num記錄的是強連通分量數量,p是記錄第幾個強連通分量裡面的點,unicom表示每一個點屬於第幾個強連通分量。
演算法複雜度O(N+E)
這樣我們的預備工作就做好了。把N個點劃分成了num個強連通分量塊了。
問了驗證有向圖的聯通性,我們還需要利用邊的資訊。
假如存a->b的邊而且unicom[a]!=unicom[b]即它們倆個點不屬於同一強連通分量。那麼也就是說我們到達了點a,那麼包括點b的強連通分量就全部可以到達了。
我們給強連通分量unicom[b]打上標記,這塊不用考慮了,考慮a就行了。
S陣列儲存起點 E陣列儲存終點 e表示邊的條數。
演算法複雜度O(E)
總時間複雜度O(E+N)
基本上這個連通性的問題就解決了,對於那些沒有打上標記的強連通分量就需要選取到達了。
程式碼如下:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+100;
vector<int> G[maxn],p[maxn],ans;
int low[maxn],dfn[maxn],Stack[maxn],S[maxn],E[maxn],n,e,cnt,Index,num;
int link[maxn],unicom[maxn];
bool vis[maxn];
void tarjan(int u)
{
low[u]=dfn[u]=++cnt;
vis[u]=true;
Stack[++Index]=u;
for (int i=0;i<G[u].size();i++) {
int v=G[u][i];
if (!dfn[v]) {
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if (vis[v]){
low[u]=min(low[u],dfn[v]);
}
}
if (dfn[u]==low[u]) {
++num;
do {
p[num].push_back(Stack[Index]);
unicom[Stack[Index]]=num;
vis[Stack[Index]]=false;
Index--;
}while (u!=Stack[Index+1]);
}
return ;
}
int main()
{
scanf("%d%d",&n,&e);
for (int i=1;i<=e;i++) {
scanf("%d%d",&S[i],&E[i]);
G[S[i]].push_back(E[i]);
}
memset (vis,false,sizeof(vis));
for (int i=1;i<=n;i++) {
if (!dfn[i]) tarjan(i);
}
for (int i=1;i<=e;i++) {
if (unicom[S[i]]!=unicom[E[i]])
link[unicom[E[i]]]=1;
}
for (int i=1;i<=num;i++) sort(p[i].begin(),p[i].end());
for (int i=1;i<=num;i++) {
if (!link[i]) ans.push_back(p[i][0]);//選取第一個點就好了
}
sort(ans.begin(),ans.end());
printf("%d\n",ans.size());
for (int i=0;i<ans.size();i++) {
printf("%d%c",ans[i],(i==ans.size()-1)?'\n':' ');
}
return 0;
}
相關文章
- 圖 - 有向圖
- 虛擬貼圖理論之貼圖壓縮
- 【知識點】圖與圖論入門圖論
- 有向圖強連通分支
- 圖-無向圖
- 判斷一個有向圖是否有環
- 有向圖的拓撲排序——DFS排序
- 有向圖的強連通性(java)Java
- 有向圖的強連通分量 模版
- Windows設定圖片縮圖Windows
- 【圖論】尤拉圖圖論
- 圖論之有權圖「帶權圖的表示及相鄰節點迭代器」圖論
- 圖論圖論
- 無向連通圖求割點和橋
- 無向連通圖點雙連通分量
- 上傳圖片 以及做成縮圖
- 拓撲排序 (BFS )DAG (有向無環圖)排序
- 有向圖的連通性(判強連通)
- Tarjan 求有向圖的強連通分量
- 用SQL解決有向圖問題(轉)SQL
- dfs列印有向圖的起點到終點路徑
- 前端圖片壓縮 - H5&Uni-App圖片壓縮前端H5APP
- SwiftUI圖片處理(縮放、拼圖)SwiftUI
- .Net 圖片縮圖上傳通用方法
- 圖論板子圖論
- 模板 - 圖論圖論
- 【模板】圖論圖論
- 10244圖論圖論
- cdr怎麼檢視圖片縮圖win10_cdr如何檢視圖片縮圖win10Win10
- 19 略縮圖高亮
- canvas 壓縮圖片Canvas
- 圖片壓縮20201109
- 網頁縮圖API網頁API
- ??圖片壓縮CanvasCanvas
- C# 生成縮圖C#
- 有向圖的基本演算法-Java實現演算法Java
- 【JavaScript】拖拽圖片檔案顯示縮圖 + div點選模擬 input[type=file]JavaScript
- SOLIDWORKS軟體如何匯出帶有縮圖的BOMSolid