最短路径

最短路径算法

两种算法的本质其实都是一种遍历,和一般的遍历不同的是,他们巧妙的保存了中间的 计算结果,因此减少了一些中间重复的计算过程

目录

1 Dijkstra算法

原理:

  1. 其实质是一种遍历,所以时间复杂度是O(n^2)
  2. 跟普通的遍历算法不同的是,它能用最小的空间,保存一个点到其他所有点的最短距离,但是无法记录路径。
  3. Dijkstra算法就像是一个波的扩散过程,每一个波的周边继续不断的扩散,然后覆盖整个区域,扩散时,每次都选择最短的边,进行扩散,以免乱。
  4. 算法步骤
    1 初始化visit数组,和边数组
    2 选择连接已访问的点S和未访问的V中最短的一条边 ,端点为u
    3 将u加到S中,重新更新邻接矩阵
    4.如果V中还有元素,重复2 3
    5.输出邻接矩阵的第一行

源码:

Java实现

import java.util.Scanner;


public class Dijisktra {


    public static void main(String[] args) {
        int[][] e = new int[10][10];  //这里简单的设置为了 静态
        int[] dis = new int[10];
        int[] book = new int[10];
        int i, j, n, m, t1, t2, t3, u = 0, v, min;
        int inf = 99999999; //用inf(infinity的缩写)存储一个我们认为的正无穷值
        //读入n和m,n表示顶点个数,m表示边的条数


        Scanner sc = new Scanner(System.in);
//        System.out.println("请输入顶点数和边数 如6 9 ");
//        n = sc.nextInt();
//        m = sc.nextInt();
        n=6;
        m=9;


        //初始化
        for (i = 1; i <= n; i++)
            for (j = 1; j <= n; j++)
                if (i == j) e[i][j] = 0;
                else e[i][j] = inf;


//        //读入边
//        System.out.println("请输入边的参数 如1 2 1");
//        for (i = 1; i <= m; i++) {
//            t1 = sc.nextInt();
//            t2 = sc.nextInt();
//            t3 = sc.nextInt();
//            e[t1][t2] = t3;
//        }

        e[1][2] = 1;
        e[1][3] = 12;
        e[2][3] = 9;
        e[2][4] = 3;
        e[3][5] = 5;
        e[4][3] = 4;
        e[4][5] = 13;
        e[4][6] = 15;
        e[5][6] = 4;






        //初始化dis数组,这里是1号顶点到其余各个顶点的初始路程
        //其实就是邻接矩阵的第一行
        for (i = 1; i <= n; i++)
            dis[i] = e[1][i];


        //book数组初始化
        //book[i]=1表示该节点已经在S中 否则就是在V中
        for (i = 1; i <= n; i++)
            book[i] = 0;
        book[1] = 1;


        //Dijkstra算法核心语句
        for (i = 1; i <= n - 1; i++) {
            //找到离1号顶点最近的顶点
            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("%4d",dis[i]);


    }


}

C++/c实现

http://wiki.jikexueyuan.com/project/easy-learn-algorithm/dijkstra.html

 #include <stdio.h>
    int main()
    {
        int e[10][10],dis[10],book[10],i,j,n,m,t1,t2,t3,u,v,min;
        int inf=99999999; //用inf(infinity的缩写)存储一个我们认为的正无穷值
        //读入n和m,n表示顶点个数,m表示边的条数
        scanf("%d %d",&n,&m);

        //初始化
        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++)
        {
            scanf("%d %d %d",&t1,&t2,&t3);
            e[t1][t2]=t3;
        }



        //初始化dis数组,这里是1号顶点到其余各个顶点的初始路程 
        //其实就是邻接矩阵的第一行
        for(i=1;i<=n;i++)
            dis[i]=e[1][i];




        //book数组初始化
        //book[i]=1表示该节点已经在S中 否则就是在V中
        for(i=1;i<=n;i++)
            book[i]=0;
        book[1]=1;




        //Dijkstra算法核心语句
        for(i=1;i<=n-1;i++)
        {
            //找到离1号顶点最近的顶点
            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++)
            printf("%d ",dis[i]);

        getchar();
        getchar();
        return 0;
    }

2 Floyd算法

原理:

  1. 对于每一对顶点 u 和 v,看看是否存在一个顶点 w 使得从 u 到 w 再到 v 比己知的路径更短。如果是更新它。 时间复杂度O(N3)
  2. 如要从0-7,先看看加入中间节点1会不会短一点,如果短一点就0-1-7,然后再看再加入一个2会不会更短一点,如果更短就0-1-2-7,以此类推直到所有的点都遍历一遍,值得注意的是如果2-7之间不是直接相连,可能暂时先不更新,而是2-5、5-7先连接,然后当扩散到以5为中心点的时候,再连接上了,再更新。floyd的算法就像是破圈法的逆方法一样,先局部的形成一些小联通区域,最后慢慢的扩大到整个范围。
  3. 算法步骤
    1初始化 邻接矩阵
    2.选择一个点作为中心点,并计算从不同的起点出发到达不同的目标点的距离 更新邻接矩阵
    3.如果中心点,没有遍历完,重复2
    4.输出邻接矩阵

源代码:

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

实现过程
这里写图片描述

Java实现

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 inf = 99999999; //用inf(infinity的缩写)存储一个我们认为的正无穷值
            //读入n和m,n表示顶点个数,m表示边的条数
//         Scanner sc = new Scanner(System.in);
//        System.out.println("请输入顶点数和边数 如6 9 ");
//        n = sc.nextInt();
//        m = sc.nextInt();
            n = 4;
            m = 8;
            //初始化
            for (i = 1; i <= n; i++)
                for (j = 1; j <= n; j++)
                    if (i == j) e[i][j] = 0;
                    else e[i][j] = inf;
            //读入边
//        System.out.println("请输入边的参数 如1 2 1");
//        for (i = 1; i <= m; i++) {
//            t1 = sc.nextInt();
//            t2 = sc.nextInt();
//            t3 = sc.nextInt();
//            e[t1][t2] = t3;
//        }
            e[1][2] = 2;
            e[1][3] = 6;
            e[1][4] = 4;
            e[2][3] = 3;
            e[3][1] = 7;
            e[3][4] = 1;
            e[4][1] = 5;
            e[4][3] = 12;

            //Floyd-Warshall算法核心语句
            //k是中间节点
            //i是源jiedian
            //j是目标节点
            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(' ');
            }


        }

    }
}

C++/C实现

http://wiki.jikexueyuan.com/project/easy-learn-algorithm/floyd.html

//注意本文给出的例子是一个有向图
 #include <stdio.h>
    int main()
    {
        int e[10][10],k,i,j,n,m,t1,t2,t3;
        int inf=99999999; //用inf(infinity的缩写)存储一个我们认为的正无穷值
        //读入n和m,n表示顶点个数,m表示边的条数
//        scanf("%d %d",&n,&m);
            n=4;
            m=8;
        //初始化
        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++)
        {
            scanf("%d %d %d",&t1,&t2,&t3);
            e[t1][t2]=t3;
        }
        */
        e[1][2]=2;
        e[1][3]=6;
        e[1][4]=4;
        e[2][3]=3;
        e[3][1]=7;
        e[3][4]=1;
        e[4][1]=5;
        e[4][3]=12;

        //Floyd-Warshall算法核心语句
        //k是中间节点
        //i是源jiedian
        //j是目标节点 
        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++)
            {
                printf("%10d",e[i][j]);
            }
            printf("\n");
        }

        return 0;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值