赋权图:与每条边 ( v i − v j ) (v_i-v_j) (vi−vj)相联系的是穿越该弧的值 c i , j c_{i,j} ci,j,一条路径 v 1 v_1 v1, v 2 v_2 v2… v n v_n vn的值为 ∑ i = 0 n − 1 = c i , i + 1 \sum_{i=0}^{n-1}=c_{i,i+1} ∑i=0n−1=ci,i+1.叫做赋权路径长,无权路径长只是路径长的边数。
无权最短路径问题
可以使用BFS,由起始边开始搜索,搜索到,其路径就+1,这也就是最短路径。 将尚未访问到的元素标记为INF。
我这里默认起始点为1,以哪里为起始点,就最先让哪个元素入队就可以了。
#include <bits/stdc++.h>
using namespace std;
const int MAX = 1e6;
const int MOD = 100003;
struct Node {
bool vis=false;//判断是否走过
int Dist = INFINITY;//最短路
int path;//上一个结点
};
vector<int> V[MAX];
queue<int> Q;
Node NodeArr[MAX];
int main() {
int m, n; cin >> m >> n;
for (int i = 1; i <= n; i++) {
int x, y; cin >> x >> y;
V[x].push_back(y);
V[y].push_back(x);
}
for (int i = 1; i <= m; i++) {
NodeArr[i].vis = false;
NodeArr[i].Dist = INFINITY;
}
Q.push(1); NodeArr[1].Dist = 0; NodeArr[1].vis = true;
while (!Q.empty()) {
int x = Q.front(); Q.pop();
for (int i = 0; i < V[x].size(); i++) {
if (NodeArr[V[x][i]].vis==false) {
NodeArr[V[x][i]].vis = true;
NodeArr[V[x][i]].Dist = NodeArr[x].Dist + 1;
NodeArr[V[x][i]].path = x;
Q.push(V[x][i]);
}
}
}
for (int i = 1; i <= m; i++)
cout << NodeArr[i].Dist << endl;
return 0;
}
无权最短路例题
P1144 最短路计数
该题就是在上述的基础之上,需要增加一个计数功能,用以计数起始点到每一个结点的最短路情况的数量。因为这题要求的是无向图,所以需要反过来push_back一次,
c
n
t
[
n
]
=
(
c
n
t
[
n
]
+
c
n
t
[
x
]
)
%
m
o
d
cnt[n]=(cnt[n]+cnt[x]) \%mod
cnt[n]=(cnt[n]+cnt[x])%mod,值得一提的是,在要求取模的时候,需要在计算过程中取模,因为计算过程中就可能造成数据过大的情况。
#include <bits/stdc++.h>
using namespace std;
const int MAX = 1e6;
const int MOD = 100003;
vector<int> V[MAX];
queue<int> Q;
bool judge[MAX];
int cnt[MAX],depth[MAX];
int main() {
int m, n; cin >> m >> n;
for (int i = 1; i <= n; i++) {
int x, y; cin >> x >> y;
V[x].push_back(y);
V[y].push_back(x);
}
for (int i = 1; i <= m; i++) sort(V[i].begin(), V[i].end());
Q.push(1); judge[1] = 1; cnt[1] = 1;
while (!Q.empty()) {
int x = Q.front(); Q.pop();
for (int i = 0; i < V[x].size(); i++) {
int n = V[x][i];
if (!judge[n]) {
judge[n] = 1;
depth[n] = depth[x] + 1;
Q.push(n);
}
if(depth[n]==depth[x]+1)
cnt[n]=(cnt[n]+cnt[x])%MOD;
}
}
for (int i = 1; i <= m; i++)
cout << cnt[i] << endl;
return 0;
}
Dijkstra算法
对于上述无权图而言,比较容易解决,但是对于开头所介绍的赋权图而言,问题就要麻烦不少。
Dijkstra算法:Dijkstra算法是通过贪心思想进行的,按阶段进行,在每个阶段,Dijkstra算法选择一个顶点v,他在所有未知顶点中具有最小的
d
v
d_v
dv,同时算法声明从s到v的最短路径是已知的,阶段的其余部分由
d
w
d_w
dw值的更新工作组成。
此算法无法求负权图。
自己用队列写了一个,思路很简单,通过起始点出发,每次结点的dist值都取起始点到达这个点的最小值,思路类似于DP,有错误请指出。
#include <bits/stdc++.h>
using namespace std;
const int MAX = 1e5;
const int INF = 1e9;
struct Node {
int path;
int dist=INF;
bool vis = false;
};
Node NodeArr[MAX];
vector<pair<int,int>> V[MAX];
queue<int> Q;
void Dijkstra(vector<pair<int, int>> V[],int start) {
Q.push(start); NodeArr[start].dist = 0; NodeArr[start].vis = true;
while (!Q.empty()) {
int x = Q.front(); Q.pop();
for (int i = 0; i < V[x].size(); i++)
{
if (NodeArr[V[x][i].first].vis == false) {
NodeArr[V[x][i].first].vis == true;
NodeArr[V[x][i].first].path = x;
int temp = NodeArr[x].dist + V[x][i].second;
if (NodeArr[V[x][i].first].dist > temp)
NodeArr[V[x][i].first].dist = temp;
Q.push(V[x][i].first);
}
}
}
}
int main() {
int n, m; cin >> n >> m;
for (int i = 1; i <= m; i++) {
int x, y,l; cin >> x >> y >> l;
V[x].push_back({ y, l });
}
Dijkstra(V, 1);
for (int i = 1; i <= n; i++) {
cout << NodeArr[i].dist;
}
return 0;
}