最短路总结
//稀疏图选用邻接表来存储要比邻接矩阵来存储要好很多
根据HDU 1874裸最短路,写了各种最短路模板
hdu 1874 畅通工程续(无向图
//Floyd
Floyd算法的学习可以点进这个链接,点这里,非常简单的算法,链接里也介绍的非常详尽^_^
//Floyd算法
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <string.h>
#include <queue>
#define N 200+5
#define inf 1<<29
using namespace std;
int e[N][N];
void inti(int n, int m)
{
int i, j, a, b, c;
for(i = 0; i < n; i++)
{
for(j = 0; j < n; j++)
e[i][j] = inf;
e[i][i] = 0;
}
while(m-->0)
{
scanf("%d%d%d", &a, &b, &c);
if(c < e[a][b])
e[a][b] = e[b][a] = c;
}
}
void floyd(int n)
{
int i, j, k;
for(k = 0; k < n; k++)
for(i = 0; i < n; i++)
for(j = 0; j < n; j++)
if(e[i][j] > e[i][k] + e[k][j])
e[i][j] = e[i][k] + e[k][j];
}
int main()
{
int n, m;
int a, b;
while(~scanf("%d%d", &n, &m))
{
inti(n,m);
floyd(n);
scanf("%d%d", &a, &b);
if(e[a][b] != inf)
printf("%d\n", e[a][b]);
else
printf("-1\n");
}
return 0;
}
//spfa
spfa的邻接表数组实现,学习链接点这里,通俗易懂,看完这个看下面写的邻接表的队列实现的储存数据那更好理解
//spfa+邻接表的数组实现
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <string.h>
#include <queue>
#define N 201
#define M 201
#define inf 1<<29
using namespace std;
int dis[N];
int u[M],v[M], w[M];
int p[N];//记录每个顶点其中一条边的编号
int next[M];//记录编号为i的边的前一条边的编号
int e;
void input(int m)
{
for(int i = 0; i < m; i++)
{
scanf("%d%d%d", &u[i], &v[i], &w[i]);
next[i] = p[u[i]];
p[u[i]] = i;
}
}
void spfa(int s)
{
int k = p[s];
while(k != -1)
{
if(dis[v[k]] > dis[s] + w[k])
{
dis[v[k]] = dis[s] + w[k];
if(v[k] != e)
spfa(v[k]);
}
k = next[k];
}
}
int main()
{
int n, m;
int s;
while(~scanf("%d%d", &n, &m))
{
memset(p,-1,sizeof(p));
fill(dis,dis+N,inf);
input(m);
scanf("%d%d", &s, &e);
dis[s] = 0;
spfa(s);
if(dis[e] != inf)
printf("%d\n", dis[e]);
else
printf("-1\n");
}
return 0;
}
//但是没过,说是complication error,编译错误,不是很懂......求大神点醒
无向图的邻接表、有向图的正逆邻接表这个博客写的不错,很清楚,实现过程也清楚,可以点这里看看
spfa中我最喜欢这个实现,如果看不懂怎么存储数据使用的,可以自己推演一遍,如果不懂就再推演,学会了会很方便^_^
//spfa+邻接表的队列实现
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <string.h>
#include <queue>
#define N 300
#define inf 1<<29
using namespace std;
struct node{
int v;
int c;
int next;//记录编号为i的边的前一条边的编号
}edge[N*2];
int dis[N];
int path[N];//记录每个顶点其中一条边的编号
int vis[N];//是否在队列中
void add(int m)
{
int i = 0;
int a, b, c;
while(m--)
{
scanf("%d%d%d", &a, &b, &c);
edge[i].v = b;
edge[i].c = c;
edge[i].next = path[a];
path[a] = i++;
edge[i].v = a;
edge[i].c = c;
edge[i].next = path[b];
path[b] = i++;
}
}
void spfa(int s)
{
dis[s] = 0;
queue<int>Q;
Q.push(s);
while(!Q.empty())
{
int t = Q.front();
Q.pop();
vis[t] = false;
for(int i = path[t]; i != -1; i = edge[i].next)
{
int w = edge[i].c;
int temp = edge[i].v;
if(dis[temp] > dis[t] + w)
{
dis[temp] = dis[t] + w;
if(!vis[temp])
{
Q.push(temp);
vis[temp] = true;
}
}
}
}
}
int main()
{
int n, m;
int s, e;
while(~scanf("%d%d", &n, &m))
{
memset(path, -1, sizeof(path));
memset(vis, false, sizeof(vis));
fill(dis, dis+N, inf);
add(m);
scanf("%d%d", &s, &e);
spfa(s);
if(dis[e] != inf)
printf("%d\n", dis[e]);
else
printf("-1\n");
}
return 0;
}
邻接矩阵的实现可以点这里学习
//spfa+邻接表的邻接矩阵实现
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <string.h>
#include <queue>
#define N 205
#define inf 1<<29
using namespace std;
int map[N][N];
int dis[N];
int vis[N];//是否在队列中
void inti(int n, int m)
{
int i, j;
int a, b, c;
memset(vis, false, sizeof(vis));
fill(dis, dis+N, inf);
for(i = 0; i < n; i++)
{
for(j = 0; j < n; j++)
map[i][j] = inf;
map[i][i] = 0;
}
while(m--)
{
scanf("%d%d%d", &a, &b, &c);
if(c < map[a][b])
map[a][b] = map[b][a] = c;
}
}
void spfa(int n, int s)
{
dis[s] = 0;
queue<int>Q;
Q.push(s);
while(!Q.empty())
{
int t = Q.front();
Q.pop();
vis[t] = false;
for(int i = 0; i < n; i++)
{
if(dis[i] > dis[t] + map[t][i] && map[t][i]!=inf)
{
dis[i] = dis[t] + map[t][i];
if(!vis[i])
{
Q.push(i);
vis[i] = true;
}
}
}
}
}
int main()
{
int n, m;
int s, e;
while(~scanf("%d%d", &n, &m))
{
inti(n, m);
scanf("%d%d", &s, &e);
spfa(n, s);
if(dis[e] != inf)
printf("%d\n", dis[e]);
else
printf("-1\n");
}
return 0;
}
//dijkstra
dijkstra的算法基本思想:每次找到离源点最近的一个顶点,以此顶点为中心扩展,更新源点到其余所有点的最短路径。具体可以看这个
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <string.h>
#include <cmath>
#include <string>
#define N 205
#define inf 1<<29
using namespace std;
//单源最短路
bool vis[N];
int map[N][N];
int dis[N];
int s, e;
void inti(int n, int m)
{
int i, j;
int a, b, c;
memset(vis, false, sizeof(vis));
fill(dis, dis+N, inf);
for(i = 0; i < n; i++)
{
for(j = 0; j < n; j++)
map[i][j] = inf;
map[i][i] = 0;
}
while(m-->0)
{
scanf("%d%d%d", &a, &b, &c);
if(map[a][b] > c)//两点之间不止一条路径
map[a][b] = map[b][a] = c;//无向图
}
scanf("%d%d", &s, &e);
///记录源点s到其余点的初始路径
for(i = 0; i < n; i++)
dis[i] = map[s][i];
vis[s] = true;
}
void dijkstra(int n)
{
int i, j, k;
int min;
int t = s;//注意赋初值
for(i = 0; i < n-1; i++)
{
//找出距离i点的最短路径点
min = inf;
for(j = 0; j < n; j++)
if(!vis[j] && dis[j] < min)
{
min = dis[j];
t = j;
}
vis[t] = true;
for(k = 0; k < n; k++)
if(dis[k] > dis[t] + map[t][k])
dis[k] = dis[t] + map[t][k];
}
}
int main()
{
int n, m;
while(~scanf("%d%d", &n, &m))
{
inti(n, m);
dijkstra(n);
if(dis[e] != inf)
printf("%d\n", dis[e]);
else
printf("-1\n");
}
return 0;
}
//待补充
//spfa+邻接表的vector模拟
补充:
关于Floyd、Dijkstra、Bellman-Ford、Spfa算法的比较,可以先看这个博客,总结的不错
简而言之:
Floyd:多源、无负权边(原理是动态规划,矩阵存,时效性差
Dijkstra:单源、无负权边(堆的运用还没怎么看...
Bellman-Ford:单源、可有负权边、无负环
Spfa:单源、可有负权边、无负环(邻接表存,Bellman的队列优化,可完全替代Bellman)