最短路问题 待整理

单源最短路

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 )
扩展

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值