最短路径

1,Floyd-Warshall算法(只有五行)

for(int k=1;k<=n;k++){
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(e[i][j]>e[i][k] + e[k][j])   
                e[i][j]=e[i][k]+e[k][j];
        }
    }
}

基本思想: 允许经过1-n号 所有顶点进行中转,求任意两点之间的最短路程,e[i][j]表示从 i顶点到 j顶点的路程。
需要注意的是: Floyd算法不能处理带有“负权回路”的图,即二维矩阵中的值不能为负数。

package 最短路径;
import java.util.*;
public class Floyd {
    public static void main(String[] args){
        int[][] e=new int[10][10];
        int k,i,j,n,m,t1,t2,t3;
        int min=99999999;
        Scanner sc=new Scanner(System.in);
        n=sc.nextInt();
        m=sc.nextInt();
        //初始化
        for(i=1;i<=n;i++){
            for(j=1;j<=n;j++){
                if(i==j)e[i][j]=0;
                else
                    e[i][j]=min;
            }
        }
        //读入边
        for(i=1;i<=m;i++){
            t1=sc.nextInt();
            t2=sc.nextInt();
            t3=sc.nextInt();
            e[t1][t2]=t3;//有向图

        }
        //Floyd-Warshall算法核心语句
        for(k=1;k<=n;k++){
            for(i=1;i<=n;i++){
                for(j=1;j<=n;j++){
                    if(e[i][j]>e[i][k]+e[k][j])
                        e[i][j]=e[i][k]+e[k][j];
                }
            }
        }

        for(i=1;i<=n;i++){
            for(j=1;j<=n;j++){
                System.out.printf("%10d",e[i][j]);
            }
            System.out.println();
        }
    }
}
4 8
1 2 2 
1 3 6 
1 4 4 
2 3 3 
3 1 7
3 4 1 
4 1 5
4 3 12 
输出:
         0         2         5         4
         9         0         3         4
         6         8         0         1
         5         7        10         0

2,Dijkstra算法-单源最短路
使用二维数组e来存储顶点之间边的关系
还需要用一个一维数组dis来存储1 号顶点到其余各个顶点的初始路程。
Dijkstra主要思想:通过“边”来松弛1 号顶点到其余各个顶点的路程。

松弛的过程:如: 要求顶点1 到顶点4 的最短路程,通过2->4(e[2][4]),可以将dis[4]的值从无穷松弛为4(dis[4]初始为无穷, dis[2]+e[2][4]=1+3=4, 由于 dis[4]>dis[2]+e[2][4],因此dis[4]更新为4)。

算法的基本思想是:每次找到离源点最近的一个顶点,然后以该顶点为中心进行扩展,最终得到源点到其余所有点的最短路径。

package 最短路径;
import java.util.*;
public class Dijkstra {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        int[][] e=new int[10][10];
        int[] dis=new int[10];
        int[] book=new int[10];
        int i,j,m,n,t1,t2,t3,min;
        int u = 0,v=0;
        int inf=99999999;
        Scanner sc=new Scanner(System.in);
        n=sc.nextInt();
        m=sc.nextInt();
        //初始化
        for(i=1;i<=n;i++){
            for(j=1;j<=n;j++){
                if(i==j)e[i][j]=0;
                else
                    e[i][j]=inf;
            }
        }
        //读入边
        for(i=1;i<=m;i++){
            t1=sc.nextInt();
            t2=sc.nextInt();
            t3=sc.nextInt();
            e[t1][t2]=t3;//有向图
        }
        //初始化dis数组,顶点1 到其余各顶点的路程
        for(i=1;i<=n;i++){
            dis[i]=e[1][i];
        }

        book[1]=1;

        //Dijkstra算法核心语句
        for(i=1;i<=n-1;i++){
            min=inf;
            for(j=1;j<=n;j++){
                if(book[j]==0 && dis[j]<min){
                    min=dis[j];
                    u=j;
                }
            }
            book[u]=1;
            for(v=1;v<=n;v++){
                if(e[u][v]<inf){
                    if(dis[v]>dis[u]+e[u][v]){
                        dis[v]=dis[u]+e[u][v];
                    }
                }
            }
        }
        for(i=1;i<=n;i++){
            System.out.printf("%d ",dis[i]);
            System.out.printf(" ");
        }
    }

}
6 9 
1 2 1 
1 3 12
2 3 9
2 4 3 
3 5 5 
4 3 4 
4 5 13
4 6 15
5 6 4
输出:
0  1  8  4  13  17  

3,Bellman-Ford–解决负权边

for(k=1;k<=n-1;k++){
    for(i=1;i<=m;i++){
        if(dis[v[i]]> dis[u[i]]+w[i])
            dis[v[i]]=dis[u[i]]+w[i];
    }
}
外循环一共循环了n-1次(n为顶点的个数), m为边的个数,
dis数组和Dijkstra算法一样,用来记录源点到其余各个顶点的最短路径。u、v、w三个数组是用来记录边的信息, 例如第i条边的信息存储在u[i] v[i] w[i]中,表示从顶点 u[i] 到顶点 v[i] 这条边(u[i]->v[i])的权值为w[i]。
if(dis[v[i]]> dis[u[i]]+w[i])
    dis[v[i]]=dis[u[i]]+w[i];
这两行代码的意思是: 看看能否通过 u[i]->v[i](权值为w[i])这条边,使得1 号顶点到 v[i]号顶点的距离变短。 即1 号顶点到u[i]号顶点的距离(dis[u[i]])加上 u[i]->v[i]这条边(权值为w[i])的值是否会比原先 1  号顶点到v[i]号顶点的距离 dis[v[i]]要小。

Bellman-Ford算法: 对所有的边进行n-1次 “松弛”操作,

for(k=1;k<=n-1;k++){//进行n-1次松弛
    for(i=1;i<=m;i++){//枚举每一条边
        if(dis[v[i]]> dis[u[i]]+w[i])//尝试对每一条边进行松弛
            dis[v[i]]=dis[u[i]]+w[i];
    }
}

完整代码

package 最短路径;
import java.util.*;
public class BelllmanFord {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        int[] dis=new int[10];
        int i,k,n,m;
        int[] u=new int[10];
        int[] v=new int[10];
        int[] w=new int[10];
        int inf=99999999;
        Scanner sc=new Scanner(System.in);
        n=sc.nextInt();
        m=sc.nextInt();
        //读入边
        for(i=1;i<=m;i++){
            u[i]=sc.nextInt();
            v[i]=sc.nextInt();
            w[i]=sc.nextInt();
        }

        //初始化dis数组,这里是1 号顶点到其余各个顶点的初始路程
        for(i=1;i<=n;i++){
            dis[i]=inf;
        }
        dis[1]=0;
        //Bellman-Ford核心算法

        for(k=1;k<=n-1;k++){
            for(i=1;i<=m;i++){
                if(dis[v[i]] > dis[u[i]]+w[i]){
                    dis[v[i]]=dis[u[i]]+w[i];
                }
            }
        }

        for(i=1;i<=n;i++){
            System.out.printf("%d", dis[i]);
            System.out.printf(" ");
        }
    }

}
5 5 
2 3 2 
1 2 -3
1 5 5
4 5 2
3 4 3
输出:
0 -3 -1 2 4 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值