单源最短路径Djikstra算法
题目链接 https://vjudge.net/problem/Aizu-ALDS1_12_B
题目描述:一个有向图G(V,E) 第一行输入节点数n,接下来n行以图的邻接表存储,第一个数为该节点的出度。输出每个顶点和距离。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <stack>
#include <vector>
using namespace std;
#define maxn 10005
#define INF 0x3f3f3f3f
int n, m[maxn][maxn];
int u, v ,k, c;
int flag[maxn];
void dijkstra() {
int d[maxn];
for (int i = 0; i < n; i++) { //初始化
d[i] = INF;
flag[i] = 0;
}
d[0] = 0;
while (1) {
int minv = INF;
u = -1;
for (int i = 0; i < n; i++) { //选出权值最小的边 v加入S
if (minv > d[i] && flag[i] == 0) {
u = i;
minv = d[i];
}
}
if (u == -1)
break;
flag[u] = 1; //标记已经加入S
for (int v = 0; v < n; v++) { //对V-S中所有顶点的距离值进行修改
if (flag[v] == 0 && m[u][v] != INF && d[v] > d[u] + m[u][v])
d[v] = d[u] + m[u][v];
}
}
for (int i = 0; i < n; i++)
printf("%d %d\n", i, d[i] == INF ? -1 : d[i]);
}
int main()
{
scanf("%d", &n);
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
m[i][j] = INF;
}
}
for (int i = 0; i < n; i++) {
scanf("%d %d", &u, &k);
for (int j = 0; j < k; j++) {
scanf("%d %d", &v, &c);
m[u][v] = c;
}
}
dijkstra();
return 0;
}
使用优先队列优化Dijkstra算法
输入 顶点总数 6 总边数 9
0 2 4
1 0 2
0 3 28
2 5 8
2 1 15
5 3 13
5 4 18
4 3 4
1 4 10
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <queue>
#include <vector>
using namespace std;
typedef long long ll;
typedef pair<int,int> p;
#define M 30005
#define INF 0x3f3f3f3f
struct edge
{
int v,next,w;
}E[150005];
int head[M];
int d[M];
int n,m,cnt;
priority_queue<p,vector<p>,greater<p> > q;
int init()
{
cnt=0;
memset(head,-1,sizeof(head));
while(!q.empty()){
q.pop();
}
}
void addedge(int u,int v,int w)
{
E[cnt].v=v;E[cnt].w=w;
E[cnt].next=head[u];
head[u]=cnt++;
}
void dijkstra(int s)
{
for(int i=1;i<=n;i++)
d[i]=INF;
d[s]=0;
q.push(make_pair(d[s],s));
while(!q.empty()){
p x=q.top();
q.pop();
int u=x.second;
if(d[u] != x.first) continue;
for(int e=head[u];e!=-1;e=E[e].next){
int t=d[u]+E[e].w;
if(d[E[e].v] > t){
d[E[e].v] =t;
q.push(make_pair(t,E[e].v));
}
}
}
}
int main()
{
scanf("%d%d",&n,&m);
init();
for(int i=0;i<m;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
addedge(u,v,w);
}
dijkstra(1);
for(int i=2;i<=n;i++)
printf("%d\n",d[i]);
return 0;
}
这个优化算法自己慢慢体会吧。。
Floyd算法
弗洛伊德算法是解决任意两点间的最短路径的一种算法。
(1)从任意一条单边路径开始。所有两点之间的距离是边的权,如果两点之间没有边相连,则权为无穷大。
(2)对于每一对顶点 u 和 v,看看是否存在一个顶点 w 使得从 u 到 w 再到 v 比已知的路径更短。如果是更新它。
核心代码
typedef int dis[M][M];
typedef int paths[M][M];
void floyd(Mgraph g,paths p,dis d)
{
int i,j,k;
for(i=0;i<g.n;i++)
for(j=0;j<g.n;j++)
{
d[i][j]=g.edges[i][j];
if(i!=j&&d[i][j]<FINITY)
p[i][j]=i;
else
p[i][j]=-1;
}
for(k=0;k<g.n;k++)
{
for(i=0;i<g.n;i++)
for(j=0;j<g.n;j++)
if(d[i][j]>(d[i][k]+d[k][j]))
{
d[i][j]=d[i][k]+d[k][j];
p[i][j]=k;
}
}
}
最短路径拓展算法
Bellman - ford算法 : 求含负权图的单源最短路径的一种算法
SPFA 算法: Bellman-Ford算法 的队列优化算法