单源最短路
1.bellman-ford(有负权边也适用,还可以用来判断负权环)
!注意如果一个图存在负权环那么这个图没有最短路概念
基本:
1.时间复杂度:T=O(|V|*|E|)
2.用于求固定点到其余点的最短路。
3.
扩展:SPFA算法
板子:
#include<bits/stdc++.h>
const int INF = 9999999;
using namespace std;
int main()
{
int u[100] , v[100] , w[100] , dis[100] , n , m , ck , flag;
cin>>n>>m;
for(int i = 1 ; i <= m ; i ++)
{
cin>>u[i] >> v[i] >> w[i];
}
//bellman求最短路
for(int i = 1 ; i <= n ; i ++)
dis[i] = INF;
dis[1] = 0;
for(int k = 1 ; k <= n - 1 ; k ++)//随着循环,dis跟着变为各点经过最多前1个点到s的最短路,经过最多前两个前三个。。经过最多前n-1个到达s的最短路。但并不是严格意义上的,大致如此。有时候循环边的顺序会影响。
{
ck = 0 ; //用来标记本轮松弛操作中数组dis是否会发生更新
for(int i = 1 ; i <= m ; i ++)
{
if(dis[v[i]] > dis[u[i]] + w[i])
{
dis[v[i]] = dis[u[i]] + w[i];
ck = 1 ; //数组dis发生更新,改变check的值
}
}
if(ck == 0)
break; //如果dis数组没有更新,提前退出循环结束算法
}
//bellman判断有无负圈
flag = 0 ;
for(int i = 1 ; i <= m ; i ++)
if(dis[v[i]] > dis[u[i]] + w[i])
flag = 1;
if(flag == 1)
printf("此图包含有负权回路\n");
else
{
for(int i = 1 ; i <= n ; i ++)
printf("%d ",dis[i]);
}
return 0 ;
}
/*
5 5
2 3 2
1 2 -3
1 5 5
4 5 2
3 4 3
*/
//时间复杂度T=O(|E|*|V|)
2.SPFA(队列优化的bellman-ford)
基本:
1.时间复杂度:通常是O(kE)。最好k=1,精心构造的图可达到k=V.
板子:
import java.io.IOException;
import java.io.InputStream;
import java.util.InputMismatchException;
import java.util.LinkedList;
import java.util.Queue;
class node{
int to,next,w;
}
public class test{
//head[i]存i点的第一条出边编号
//edge[i]存第i条边的入点编号、其出点的下一条出边的编号、其权值。
public static int INF=(1<<30)-1,n,m,p,q,count=1,maxn=1000100,d[]=new int[maxn],head[]=new int[maxn];
public static node edge[]=new node[maxn];
public static Queue<Integer> que=new LinkedList<Integer>();
public static boolean vis[]=new boolean[maxn];
public static void bellman() {
que.clear();
for(int i=1;i<=n;i++) {
d[i]=INF;
vis[i]=false;
}
d[1]=0;
que.add(1);
vis[1]=true;
while(!que.isEmpty()) {
int q=que.poll();
vis[q]=false;
//找以q点为出点的所有边的入点,对这个点的d值更新。
//如果d不在队列中,则让d进队。
for(int i=head[q];i!=-1;i=edge[i].next){
int to=edge[i].to;
int w=edge[i].w;
if(d[to]>d[q]+w){//注意不要把d[q]写成d[i]!!!!
d[to]=d[q]+w;
if(!vis[to]){
vis[to]=true;
que.add(to);
}
}
}
}
}
public static void main(String args[]) {
InputReader sc=new InputReader(System.in);
int T=sc.nextInt();
while(T-->0) {
n=sc.nextInt();
m=sc.nextInt();
for(int i=1;i<=n;i++) {
head[i]=-1;
}
int u[]=new int[maxn],v[]=new int[maxn],w[]=new int[maxn];
for(int i=1;i<=m;++i) {
u[i]=sc.nextInt();
v[i]=sc.nextInt();
w[i]=sc.nextInt();
edge[i]=new node();
edge[i].to=v[i];
edge[i].next=head[u[i]];
edge[i].w=w[i];
head[u[i]]=i;
}
bellman();
//到此就获得了d[]数组。
}
}
}
多源最短路
1.floyd(有负权边也适用)
基本:
1.时间复杂度
T=O(|V|3 )
扩展