Dijkstra
时间复杂度 O( v 2 v^2 v2)
最短距离:
领接矩阵:
//邻接矩阵
const int MAXV = 1000;//最大顶点数
const int INF = 0x3fffffff;//INF为无穷大
int n,G[MAXV][MAXV];//n为顶点数,maxv为最大顶点数
int d[MAXV];//起点到各点的最短路径长度
bool vis[MAXV] = {false};//标记数组 是否已访问
void dijkstra(int s){//s为起点
fill(d,d+maxv,INF);//起始点之间均不可达
d[s] = 0;//起点s到自身距离0
for(int i=0;i<n;i++){
int u=-1,MIN = INF;//u使d[u]最小,MIN中存放最小的d[u]
//找到未访问顶点中d[]最小的
for(int j=0;j<n;j++){
if(vis[j] == false&& d[j]<MIN){
u=j;
MIN=d[j];
}
}
//找不到小于INF的d[u],说明剩下的顶点和起点s不连通
if(u==-1)
return;
//标记u为已访问
vis[u] = true;
for(int v=0;v<n;v++){
//如果v未访问&&u能到达v&&以u为中介点可以使d[v]更优
if(vis[v] == false && G[u][v] != INF && d[u]+G[u][v]<d[v]){
d[v] = d[u]+G[u][v];//优化d[v]
}
}
}
}
邻接表:
//邻接表版
struct Node{
int v,dis;//v为边的目标顶点,dis为权
};
vector<Node> Adj[MAXV];//图G,Adj[u]存放从顶点u出发可以到达的所有顶点
int n;//n为顶点数,图G使用邻接表实现,MAXV为最大顶点数
int d[MAXV];//起点到达各点的最短路径长度
bool vis[MAXV] = {false};//标记访问数组
void dijkstra(int s){//s为起点
fill(d,d+maxv,INF);//起始点之间均不可达
d[s] = 0;//起点s到自身距离0
for(int i=0;i<n;i++){
int u=-1,MIN = INF;//u使d[u]最小,MIN中存放最小的d[u]
//找到未访问顶点中d[]最小的
for(int j=0;j<n;j++){
if(vis[j] == false&& d[j]<MIN){
u=j;
MIN=d[j];
}
}
//找不到小于INF的d[u],说明剩下的顶点和起点s不连通
if(u==-1)
return;
//标记u为已访问
vis[u] = true;
for(int j=0;j<Adj[u].size();j++){
int v = Adj[u][j].v;//通过邻接表直接获得u能到达的顶点v
if(vis[v] == false && d[u]+Adj[u][j].dis<d[v]){
//如果v未访问&&以u未中介点可以使d[v]更优
d[v] = d[u]+Adj[u][j].dis;
}
}
}
}
最短路径:
在最短距离的基础上记录前驱结点即可。
以邻接矩阵为例:
//邻接矩阵
const int MAXV = 1000;//最大顶点数
const int INF = 0x3fffffff;//INF为无穷大
int n,G[MAXV][MAXV];//n为顶点数,maxv为最大顶点数
int d[MAXV];//起点到各点的最短路径长度
bool vis[MAXV] = {false};//标记数组 是否已访问
int pre[MAXV];//pre[v]表示从起点到顶点v的最短路径上v的前一个顶点
void dijkstra(int s){//s为起点
fill(d,d+maxv,INF);//起始点之间均不可达
for(int i=0;i<n;i++)
pre[i] = i;//初始状态设每个点的前驱为自身
d[s] = 0;//起点s到自身距离0
for(int i=0;i<n;i++){
int u=-1,MIN = INF;//u使d[u]最小,MIN中存放最小的d[u]
//找到未访问顶点中d[]最小的
for(int j=0;j<n;j++){
if(vis[j] == false&& d[j]<MIN){
u=j;
MIN=d[j];
}
}
//找不到小于INF的d[u],说明剩下的顶点和起点s不连通
if(u==-1)
return;
//标记u为已访问
vis[u] = true;
for(int v=0;v<n;v++){
//如果v未访问&&u能到达v&&以u为中介点可以使d[v]更优
if(vis[v] == false && G[u][v] != INF && d[u]+G[u][v]<d[v]){
d[v] = d[u]+G[u][v];//优化d[v]
pre[v] = u;//记录v的前驱顶点是u--关键
}
}
}
}
//访问前驱结点
void dfs(int s, int v){
if(v == s){//如果当前已经到达起点s,则输出起点并返回
printf("%d\n",s);
return;
}
DFS(s,pre[v]);
printf("%d\n",v);
}
邻接表完全版:
#include<stdio.h>
#include<iostream>
#include<vector>
using namespace std;
const int maxn=1000;
const int INF = 0x3fffffff;
struct E{
int dis;//距离
int v;//目标顶点
};
vector<E> Adj[maxn];
bool vis[maxn]={false};//访问数组
int d[maxn];//最短距离
int pre[maxn];//前驱结点
int n;//顶点个数
void dijkstra(int s){//算法最短路
for(int i=0;i<n;i++){
pre[i] = i;
}
for(int i=0;i<n;i++){
d[i] = INF;
}
for(int i=0;i<n;i++){
vis[i] = false;
}
d[s]=0;//到达自身距离为0
for(int i=0;i<n;i++){
int mini=-1,min=INF;
for(int j=0;j<n;j++){//寻找最小结点
if(min>d[j]&&vis[j]==false){
mini=j;
min=d[j];
}
}
if(mini==-1){//找不到最短路径
return;
}
vis[mini]=true;
for(int j=0;j<Adj[mini].size();j++){
int u=Adj[mini][j].v;
if(d[u]>d[mini]+Adj[mini][j].dis&&vis[u]==false){
d[u]=d[mini]+Adj[mini][j].dis;
pre[u]=mini;
}
}
}
}
void vispre(int v,int u){//目标结点 当前结点
if(v==u){
printf("%d ",u);
return;
}
vispre(pre[v],u);
printf("%d ",v);
}
int main(){
int m,s;//边数,起始点
while(scanf("%d%d%d",&n,&m,&s)!=EOF){
E edge;
for(int i=0;i<m;i++){
int t;
scanf("%d",&t);
scanf("%d%d",&edge.v,&edge.dis);
Adj[t].push_back(edge);
}
dijkstra(s);
int v;
scanf("%d",&v);
vispre(v,s);
printf("\n");
}
return 0;
}
若有两条以上的最短路径,题目必会给出其他条件:
(1)每条边在加一个边权,如:花费
//增加c[]记录开销
for(int v=0;v<n;v++){
if(vis[v] == false && G[u][v] != INF){
if(d[u]+G[u][v]<d[v]){
d[v] = d[u] +G[u][v];
c[v] = c[u] + cost[u][v];
}
esle if(d[u]+G[u][v] == d[v] && c[u]+cost[u][v]<c[v]){
c[v] = c[u]+cost[u][v];
}
}
}
(2) 新增点权,例如每个城市能搜集到的物资
//增加w[]记录物资
for(int v=0;v<n;v++){
if(vis[v] == false && G[u][v] != INF){
if(d[u]+G[u][v]<d[v]){
d[v] = d[u] +G[u][v];
w[v] = w[u] + cost[u][v];
}
esle if(d[u]+G[u][v] == d[v] && w[u]+weight[v]>w[v]){
w[v] = w[u]+weight[v];
}
}
}
(3)考察最短路径条数
//增加num[]记录路径条数
for(int v=0;v<n;v++){
if(vis[v] == false && G[u][v] != INF){
if(d[u]+G[u][v]<d[v]){
d[v] = d[u] +G[u][v];
num[v] = num[u];
}
esle if(d[u]+G[u][v] == d[v]){
num[v] += num[u];
}
}
}
Floyd
简洁整齐,但要注意顺序不要写反
void floyd(){//简洁 整齐
for(int k=0;k<n;k++){
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(dis[i][k]!=INF && dis[k][j] != INF && dis[i][k] + dis[k][j] <dis[i][j]){
dis[i][j] = dis[i][k] + dis[k][j];
}
}
}
}
}