例题可以用洛谷P3371和P4779
1.dijstra
完美做出,但条件是不能有负权边,堆优化以后复杂度是O(mlogn)。
2.bellman-ford
主要用于有负权边的情况,理论复杂度是O(nm),但队列优化以后往往远小于这个复杂度。
3.floyd
多源最短路算法,这里也拿过来一块学了,复杂度是 O(n3) O ( n 3 ) ,所以不应该用多元最短路算法floyd去求高效率的单源最短路。
dijkstra-heap
#include
#include
#include
#include
#include
#include
#include
#define _for(i,a,b) for(int i = (a); i<(b); i++)
#define _rep(i,a,b) for(int i = (a); i<=(b); i++)
using namespace std;
const int maxn = 100000+10;
const int maxm = 500000+10;
struct edge{
int u,v,w;
edge(int u, int v, int w):u(u), v(v), w(w){};
};
struct HeapNode{
int d, u;
bool operator <(const struct HeapNode& rhs) const{
return d > rhs.d;
}
};
int n,m,start, d[maxn];
bool done[maxn];
vector edges;
vector<int> G[maxn];
void dijkstra(int s){
priority_queue Q;
//_for(i,0,n) d[i] = INF;
d[s] = 0;
Q.push((HeapNode){0,s}); // 高端操作
while(!Q.empty()){
HeapNode x = Q.top(); Q.pop();
int u = x.u;
if(done[u]) continue;
done[u] = true;
_for(i,0,G[u].size()){
edge& e = edges[G[u][i]];
if (d[e.v] > d[u] + e.w){
d[e.v] = d[u] + e.w;
Q.push((HeapNode){d[e.v], e.v});
}
}
}
}
int main(){
scanf("%d%d%d",&n,&m,&start);
int u,v,w;
_for(i,0,m){
scanf("%d%d%d",&u,&v,&w);
G[u].push_back(edges.size());
edges.push_back(edge(u,v,w));
}
_rep(i,1,n) d[i] = 2147483647;
dijkstra(start);
_rep(i,1,n){
printf("%d ",d[i]);
}
printf("\n");
return 0;
}
bellman-ford
// O(nm)
#include
#include
#include
#include
#include
#include
#include
#define _for(i,a,b) for(int i = (a); i<(b); i++)
#define _rep(i,a,b) for(int i = (a); i<=(b); i++)
using namespace std;
const int INF = 2147483647;
const int maxn = 100000+10;
const int maxm = 500000+10;
struct edge{
int u,v,w;
edge(int u, int v, int w):u(u), v(v), w(w){};
};
int n,m,start,u[maxm],v[maxm],w[maxm],d[maxn];
int main(){
scanf("%d%d%d",&n,&m,&start);
int uu,vv,ww;
_for(i,0,m){
scanf("%d%d%d",&uu,&vv,&ww);
u[i] = uu; v[i] = vv; w[i] = ww;
}
_rep(i,1,n) d[i] = INF;
d[start] = 0;
_for(k,0,n-1) // 迭代n-1次
_for(i,0,m){ // 检查每条边
int x = u[i], y = v[i];
if( d[x] < INF ) d[y] = min(d[y], d[x]+w[i]);
}
_rep(i,1,n){
printf("%d ",d[i]);
}
printf("\n");
return 0;
}
bellman-ford + FIFO queue
#include
#include
#include
#include
#include
#include
#include
#define _for(i,a,b) for(int i = (a); i<(b); i++)
#define _rep(i,a,b) for(int i = (a); i<=(b); i++)
using namespace std;
const int INF = 2147483647;
const int maxn = 100000+10;
const int maxm = 500000+10;
struct edge{
int u,v,w;
edge(int u, int v, int w):u(u), v(v), w(w){};
};
int n,m,start, d[maxn], cnt[maxn];
bool inq[maxn];
vector edges;
vector<int> G[maxn];
bool bellman_ford(int s){
queue<int> Q;
inq[s] = true;
Q.push(s);
while(!Q.empty()){
int u = Q.front(); Q.pop();
inq[u] = false;
_for(i,0,G[u].size()){
edge &e = edges[G[u][i]];
if(d[u] < INF && d[e.v] > d[u] + e.w){
d[e.v] = d[u] + e.w;
if(!inq[e.v]) {
Q.push(e.v);
inq[e.v] = true;
if (++cnt[e.v] > n) return false; // 发现负环时及时退出?
}
}
}
}
return true;
}
int main(){
scanf("%d%d%d",&n,&m,&start);
int u,v,w;
_for(i,0,m){
scanf("%d%d%d",&u,&v,&w);
G[u].push_back(edges.size());
edges.push_back(edge(u,v,w));
}
_rep(i,1,n) d[i] = INF;
d[start] = 0;
bellman_ford(start);
_rep(i,1,n){
printf("%d ",d[i]);
}
printf("\n");
return 0;
}
floyd
(注意不能有自边)
#include
#include
#include
#include
#include
#define _for(i,a,b) for(int i = (a); i<(b); i++)
#define _rep(i,a,b) for(int i = (a); i<=(b); i++)
using namespace std;
const int INF = 2147483647;
const int maxn = 2000+10;
int n, m, start, d[maxn][maxn];
int main(){
scanf("%d%d%d",&n,&m,&start);
int u,v,w;
_rep(i,1,n) _rep(j,1,n) d[i][j] = INF;
_rep(i,1,n) d[i][i] = 0;
_for(i,0,m){
scanf("%d%d%d",&u,&v,&w);
if (u == v) continue; // floyd需要排除自边
if (d[u][v] < w) continue; // 用矩阵表示的图还要防止重边
d[u][v] = w;
}
_rep(k,1,n)
_rep(i,1,n)
_rep(j,1,n)
if(d[i][k] < INF && d[k][j] < INF)
d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
_rep(i,1,n) printf("%d ",d[start][i]);
printf("\n");
return 0;
}
好久不见