单源最短路
所有权边为正权边
稠密图(意为边很多,边m约等于点n的平方)
朴素Dijkstra算法: O(n^2)
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=510;
int g[N][N],dist[N];
int n,m;
bool st[N];
int dijkstra(){
memset(dist,0x3f,sizeof dist);
dist[1]=0;
for(int i=0;i<n;i++){
int t=-1;
for(int j=1;j<=n;j++){ //寻找到当前最近未查询点t
if(!st[j]&&(t==-1||dist[j]<dist[t])) t=j;
}
for(int j=1;j<=n;j++){
dist[j]=min(dist[j],dist[t]+g[t][j]); //确认t,并更新相应距离
}
st[t]=true;
}
if(dist[n]==0x3f3f3f3f) return -1;
else return dist[n];
}
int main(){
memset(g,0x3f,sizeof g);
scanf("%d%d",&n,&m);
while(m--){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
g[x][y]=min(g[x][y],z);
}
printf("%d\n",dijkstra());
return 0;
}
稀疏图(边m约等于点n)
堆优化Dijkstra算法 O=(mlogn)
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int N=1e6+10;
int n,m;
typedef pair<int,int> pii;
int e[N],ne[N],idx,h[N];
int dist[N],w[N];
bool st[N];
void add(int x,int y,int z){
e[idx]=y,ne[idx]=h[x],w[idx]=z,h[x]=idx++;
}
int dijkstra(){ //用小根堆优先存储dist来优化dijkstra
memset(dist,0x3f,sizeof dist);
dist[1]=0;
priority_queue<pii,vector<pii>,greater<pii>> heap;
heap.push({0,1});
while(heap.size()){
auto t=heap.top();
heap.pop();
int ver=t.second,distance=t.first;
if(st[ver]) continue;
st[ver]=true;
for(int i=h[ver];i!=-1;i=ne[i]){
int j=e[i];
if(dist[j]>dist[ver]+w[i]){
dist[j]=dist[ver]+w[i];
heap.push({dist[j],j});
}
}
}
if(dist[n]==0x3f3f3f3f) return -1;
else return dist[n];
}
int main(){
scanf("%d%d",&n,&m);
memset(h,-1,sizeof h);
while(m--){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
}
printf("%d\n",dijkstra());
return 0;
}
存在负权边
Bellman-Ford算法 O(nm)
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=510,M=1e5+10;
struct Edge{
int a,b,c;
}edges[M];
int n,m,k;
int dist[N];
int last[N];
void bellman_ford(){
dist[1]=0;
for(int i=0;i<k;i++){ //松弛k次,每次走一步
memcpy(last,dist,sizeof dist);
for(int j=0;j<m;j++){ //注意要备份,防止串联
auto e=edges[j];
dist[e.b]=min(dist[e.b],last[e.a]+e.c);
}
}
}
int main(){
memset(dist,0x3f,sizeof dist);
scanf("%d%d%d",&n,&m,&k);
for(int i=0;i<m;i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
edges[i]={x,y,z};
}
bellman_ford();
if(dist[n]>0x3f3f3f3f/2){
printf("impossible\n");
}
else printf("%d",dist[n]);
return 0;
}
优化版
SPFA O(m)---O(nm)
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int N=1e5+10;
int e[N],ne[N],idx,h[N];
int dist[N],w[N],n,m;
bool st[N];
int spfa(){ //用队列更新所有点
memset(dist,0x3f,sizeof dist);
dist[1]=0;
queue<int> q;
q.push(1);
st[1]=true;
while(q.size()){
int t=q.front();
q.pop();
st[t]=false;
for(int i=h[t];i!=-1;i=ne[i]){
int j=e[i];
if(dist[j]>dist[t]+w[i]){
dist[j]=dist[t]+w[i];
if(!st[j]){
q.push(j);
st[j]=true;
}
}
}
}
return dist[n];
}
void add(int a,int b,int c){
e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++;
}
int main(){
scanf("%d%d",&n,&m);
memset(h,-1,sizeof h);
while(m--){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);
}
int t=spfa();
if(t==0x3f3f3f3f) printf("impossible\n");
else printf("%d",t);
return 0;
}
多源汇最短路
Floyd算法 O(n^3)
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=210,INF=1e9;
int d[N][N];
int n,m,k;
void floyd(){
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
}
}
}
}
int main(){
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i==j) d[i][j]==0;
else d[i][j]=INF;
}
}
while(m--){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
d[x][y]=min(d[x][y],z);
}
floyd();
while(k--){
int a,b;
scanf("%d%d",&a,&b);
if(d[a][b]>=INF/2) printf("impossible\n");
else printf("%d\n",d[a][b]);
}
return 0;
}