BFS 和 Dijkstra's演算法
給那些點與點之間有邊(有方向性)
求可不可以從一點走到一點
#include <bits/stdc++.h>
#define endl '\n'
#define maxn 805
using namespace std;
int n, m, n1, n2; bool found, vis[maxn];
// vis存有沒有走過這個點
int main(){
ios::sync_with_stdio(0); cin.tie(0);
while(cin >> n >> m){
found=false; vector<int> v[maxn]; queue<int> q;
//v存點之間有沒有邊 (鄰接陣列存,省空間)
//q來做BFS
for (int i=1; i<=n; ++i) vis[i] = 0;
for (int i=1; i<=m; ++i){
int a, b; cin >> a >> b;
v[a].push_back(b);
}
//先將第一個點推到q裡,將vis的第一個點設為true
cin >> n1 >> n2; q.push(n1); vis[n1] = 1;
while (!q.empty()){ //重複直到q是空的
int x=q.front(); q.pop();
for (int i:v[x]){ //檢查全部x相鄰的點
if (vis[i] == 1) continue; //如果已經經過則跳過
if (i == n2){ //找到我們要的終點
found=true;
break;
}
vis[i] = 1;
q.push(i); //把x相鄰的點全部推到q
}
if (found) break;
}
if (found) cout << "Yes!!!" << endl;
else cout << "No!!!" << endl;
}
}
# Code yaaaaa
當我說距離:出發點到那一點的距離
1. 將1到n的距離存到dist[n],並將dist全部設成無限 (dist[1]=0)
2. A連接B和C,將B,C更新:
可將dist[2]更新為4,dist[3]更新為8 (4<inf, 8<inf)
3. B距離最小,將B相鄰的點都更新
(因為C的8小於4+11,所以不用更新,也不用再加到pq)
並且若我們走過的點,則不用更新
4. C距離最小,所以對C做一樣的事
(A, B走過,不用更新)
5. F距離最小
6. I距離最小
7. D距離最小
8. E距離最小
9. H距離最小
10. J距離最小
假設一個B點,可以再被更新,那圖上的點一定會有一個小於B的距離(因為有說權值一定是0或正的),所以圖上的那一個點會先去處理,因此當B點為全部點距離最小時,可以保證現在的距離是出發點到B點的最短距離 (同時也不用再更新B點了)
由上面可以得知:
#include <bits/stdc++.h>
#define endl '\n'
#define maxn 100005
#define inf LLONG_MAX
#define int long long
using namespace std;
int n, m, dist[maxn]; vector<pair<int, int>> f[maxn]; bool vis[maxn];
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
//f[i]存{j, i到j的距離}
//pq存{0到i到距離, i}
signed main(){
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
cin >> n >> m;
for (int i=1; i<=m; ++i){
int a, b, c; cin >> a >> b >> c;
f[a].push_back({b, c});
}
for (int i=1; i<=n; ++i) dist[i] = inf;
dist[1] = 0;
pq.push({0, 1});
while (!pq.empty()){
int p = pq.top().second; pq.pop(); //我們只需要pq最上面的點,距離是用來sort的
if (vis[p] == 1) continue;
//因為有可能有重複的點被放到pq,我們只需要處裡距離最小的,
//且pq的距離是由小排到大的,所以我們若造訪過就不用更新旁邊的了
vis[p] = 1; //設為造訪過
for (int i=0; i<f[p].size(); ++i){
int v=f[p][i].first; //要更新的點
int d=f[p][i].second; //現在點到要更新的點的距離
//若沒有參訪過,且新的距離小於原本的
if (vis[v] == 0 && dist[p]+d < dist[v]){
dist[v] = dist[p]+d; //更新dist
pq.push({dist[v], v}); //推進pq
}
}
}
for (int i=1; i<=n; ++i){
if (i==n) cout << dist[n] << endl;
else cout << dist[i] << " ";
}
}
# Code yaaaaa
#include <bits/stdc++.h>
#define endl '\n'
#define maxn 100005
#define inf LLONG_MAX
#define int long long
using namespace std;
int n, m, dist[maxn], path[maxn]; vector<pair<int, int>> f[maxn]; bool vis[maxn]; vector<int> final_path;
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
signed main(){
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
cin >> n >> m;
for (int i=1; i<=m; ++i){
int a, b, c; cin >> a >> b >> c;
f[a].push_back({b, c});
}
for (int i=1; i<=n; ++i) dist[i] = inf;
dist[1] = 0;
pq.push({0, 1});
while (!pq.empty()){
int p = pq.top().second; pq.pop();
if (vis[p] == 1) continue;
vis[p] = 1; path[1] = 0;
for (int i=0; i<f[p].size(); ++i){
int v=f[p][i].first;
int d=f[p][i].second;
if (vis[v] == 0 && dist[p]+d < dist[v]){
dist[v] = dist[p]+d;
path[v] = p; //加這一行
pq.push({dist[v], v});
}
}
}
//輸出1到n點最短距離和路徑
cout << dist[n] << endl;
int x=n; //從n往回找
while (x != 0){ //path[1] = 0
final_path.push_back(x);
x = path[x];
}
//反向的輸出
for (int i=final_path.size()-1; i>=0; --i){
if (i==0) cout << final_path[i] << endl;
else cout << final_path[i] << " ";
}
}
# Code yaaaaa
我的hackmd筆記: