AcWing: BFS相關
阿新 • • 發佈:2020-12-07
AcWing: BFS相關
背景知識:有向圖
離散數學圖論中的概念,由點和邊組成圖,其中圖中所有邊都是帶有方向的圖稱為有向圖。
在演算法題中,我們可以用鄰接矩陣和鄰接表(推薦)儲存有向圖。
鄰接表即類似於雜湊表的拉鍊法,用連結串列來解決衝突問題。並且其中的連結串列順序並不重要(儲存相鄰點),對於解決bfs問題來說。
寬搜框架
例題一:圖中點的層次
#include<cstring> #include<iostream> #include<algorithm> using namespace std; const int N = 100010; //兩層節點體系:一層為idx;一層為有向圖中點的編號存在e[N]中 int n, m; int h[N], e[N], ne[N], idx; //h[N]為雜湊表,e[N]用來存節點指向的節點在有向圖中的編號,ne[N]為領接表上的next,idx為當前用到的節點數 int d[N], q[N]; //q[N]為佇列儲存bfs搜尋過程,d[N]標識點是否被搜尋過,記錄到點1的距離 void add(int a, int b) //將邊a指向b加入鄰接表中 { e[idx] = b, ne[idx] = h[a], h[a] = idx++; } int bfs() { int hh = 0, tt = 0;//初始化queue佇列 q[0] = 1; memset(d, -1, sizeof d); d[1] = 0; while(hh <= tt) { int t = q[hh ++];//bfs用佇列彈出跳到下一層搜 for(int i = h[t]; i != -1; i = ne[i])//bfs一般都是用for在當前層搜 { int j = e[i]; if(d[j] == -1) { d[j] = d[t] + 1;//距離加1,可以得到點1到所有點的距離,儲存在陣列d[N]中,也完成了這一層的搜尋 //對當前層來說t的值是固定的,所以是按層搜尋,下一層t的值會變為隊頭的元素值,之前的隊頭已經出隊了 q[++tt] = j; } } } return d[n]; } int main() { cin >> n >> m; memset(h, -1, sizeof h);//初始化h[N]雜湊表,-1代表指向為空null for(int i = 0; i < m; i ++) //存入有向圖 { int a, b; cin >> a >> b; add(a, b); } cout << bfs() << endl; return 0; }
例題二:拓撲序列
#include<cstring> #include<iostream> #include<algorithm> using namespace std; const int N = 100010; int n, m; int h[N], e[N], ne[N], idx; int q[N], d[N];//d[N]記錄有向圖中編號為i的點的入度 void add(int a, int b) { e[idx] = b, ne[idx] = h[a], h[a] = idx++; } bool topsort() { int hh = 0, tt = -1;//tt表示佇列中加入的點數-1 for(int i = 1; i <= n; i ++)//把入度為0的點加入佇列中 if(!d[i]) q[++tt] = i; while(hh <= tt) { int t = q[hh++];//用彈出隊頭來搜尋下一次層 for(int i = h[t]; i != -1; i = ne[i])//用for來進行當前層搜尋 { int j = e[i]; d[j] --; //以入度減1表示該點搜過了,看習題課尋求答疑 if(d[j] == 0) q[++tt] = j; //將入度為0的點加入佇列 } } return tt == n - 1;//如果為true,代表n個點全部加入了佇列中 } int main() { cin >> n >> m; memset(h, -1, sizeof h); for(int i = 0; i < m; i ++) { int a, b; cin >> a >> b; add(a, b); d[b] ++;//順帶記錄入度 } if(topsort()) { for(int i = 0; i < n; i++) printf("%d ", q[i]); puts(""); } else puts("-1"); return 0; }