我是怎么使用最短路径算法解决动态联动问题的

  省市县三级联动问题相信大家都耳熟能详了,选择市下拉选项依赖于省,同样的选择县下拉选项依赖于市。把省市县抽象成三个节点A(省),B(市),C(县),它们的关系如下图(1)。假如把这个联动问题复杂化一点如图(2)所示,现在随便改变一个节点的值,其余节点的值会发生什么变化,你还能直接说出来吗?这个问题就是本篇将要介绍的动态联动问题。

阅读目录

  • 动态联动问题分析
  • 问题转化
  • 最短路径算法实现
  • 总结

回到顶部

动态联动问题分析

  动态联动相对于普通的联动体现在关系事先不可知,省市县联动改变什么相应联动什么都是事先知道的,所以代码实现是相对很简单的。前台写三个Select标签,每个Select标签绑定onchange事件实现相应的逻辑。

    <div>
        <select id="selProvince" onchange="changeCity()">
            <option></option>
        </select>
        <select id="selCity" onchange="changeArea()">
            <option></option>
        </select>
        <select id="selArea">
            <option></option>
        </select>
    </div>
    <script>
        function changeCity() {
            var Province = $("#selProvince").val();
            //取数,取出该省对应的市
            var data = getData(Province);
            //绑定选择城市下拉选择项
            bindCity(data);
            //清空县下拉选择项和值
            clearArea();
        }

        function changeArea() {
            var City = $("#selCity").val();
            //取数,取出该市对应的县
            var data = getData(City);
            //绑定选择县下拉选择项
            bindArea(data);
        }
    </script>

上面的两个函数代码是类似的,总结一下会发现以下步骤:

 1.获取当前改变项的值(省)

2.找出其直接影响的项(市),从后台获取对应数据,进行绑定。

3.找出其间接影响的项(县),将其下拉选择项清空,值清空

动态联动问题的难点在于第二步第三步,怎么找当前改变项的直接影响节点和间接影响节点。

回到顶部

问题转化

我们用图来描述联动,上图2中改变A节点的值,哪些是直接影响节点和间接影响节点呢。直接节点:B,间接节点C F。这里可能存在一个疑惑点C节点为什也算是间接节点呢,它不是也可以直接由A->C吗。从实际应用来考虑,从A节点到C节点有两条路径A->C,A->B->C。也就是说C是依赖于A,B两个节点的,改变了A的值,我们可以获取到B的下拉选项的值,注意了这个时候用户是没有选择B的值的,也是就说B是空的,所以是算不出来C的下拉选项的值的。不明白的可以从省市县联动来考虑,改变了省是求不出来县的值的,只能求出市。到这里可以给上面说了很多次的直接影响节点和间接影响节点下定义了

直接影响节点:改变节点到该节点不存在中转节点

    间接影响节点:改变节点到该节点存在中转节点

    无影响节点   :改变节点不能到达的节点

定义图的边路径长度为1,上面三种节点的定义可以改为

直接影响节点:最远距离=1

    间接影响节点:最远距离>1

    无影响节点   :最远距离 =无穷大

回到顶部

最短路径算法实现

经过分析我们把动态联动问题转换成了最远路径问题,这个时候解决方案就很明确了,图的最短路径算法(最远路径可以先把路径值变成相反值,再求最短路径)。当然要求最短路径就得要求图是无闭环的,如何判断图存在闭环可以参考我的另一篇文章拓扑排序及其实际应用

最短路径算法经典的有Dijkstra and Floyd算法,Dijkstra算法适合求单个节点到其它节点的最短路径问题,Floyd算法适合求每个节点到其它节点最短路径问题。

Floyd算法的基本思想如下:从任意节点A到任意节点B的最短路径不外乎2种可能,1是直接从A到B,2是从A经过若干个节点到B,所以,我们假设dist(AB)为节点A到节点B的最短路径的距离,对于每一个节点K,我们检查dist(AK) + dist(KB) < dist(AB)是否成立,如果成立,证明从A到K再到B的路径比A直接到B的路径短,我们便设置 dist(AB) = dist(AK) + dist(KB),这样一来,当我们遍历完所有节点K,dist(AB)中记录的便是A到B的最短路径的距离。

上图的邻接矩阵表示方法:

代码实现

static int M = 6;

        static void Main(string[] args)
        {
            int[,] dist = new int[6, 6]{
                {int.MaxValue,1,1,int.MaxValue,int.MaxValue,int.MaxValue},
                {int.MaxValue,int.MaxValue,1,int.MaxValue,int.MaxValue,int.MaxValue},
                {int.MaxValue,int.MaxValue,int.MaxValue,int.MaxValue,int.MaxValue,1},
                {int.MaxValue,int.MaxValue,1,int.MaxValue,int.MaxValue,int.MaxValue},
                {int.MaxValue,int.MaxValue,int.MaxValue,int.MaxValue,int.MaxValue,int.MaxValue},
                {int.MaxValue,int.MaxValue,int.MaxValue,int.MaxValue,int.MaxValue,int.MaxValue}
            };

            int[,] g = new int[6, 6];
            Floyd(dist, g);
            PrintGraph(g, M);
            Console.Read();
        }

        /// <summary>
        /// 输出最短路径矩阵
        /// </summary>
        /// <param name="g"></param>
        /// <param name="v"></param>
        public static void PrintGraph(int[,] g, int v)
        {
            for (int i = 0; i < v; i++)
            {
                for (int j = 0; j < v; j++)
                {
                    if (g[i, j] == int.MaxValue)
                        Console.Write("*" + " ");
                    else
                        Console.Write(g[i, j] + " ");
                }
                Console.WriteLine();
            }
        }

/// <summary>
        /// Floyd最短路径算法
        /// </summary>
        /// <param name="dist">邻接矩阵</param>
        /// <param name="D">最短路径</param>
        public static void Floyd(int[,] dist, int[,] D)
        {
            //复制一份dist
            for (int i = 0; i < M; i++)
            {
                for (int j = 0; j < M; j++)
                {
                    D[i, j] = dist[i, j];
                }
            }
            for (int k = 0; k < M; k++)
            {
                for (int i = 0; i < M; i++)
                {
                    for (int j = 0; j < M; j++)
                    {
                        D[i, j] = Math.Min(D[i, j], (D[i, k] == int.MaxValue || D[k, j] == int.MaxValue) ? int.MaxValue : D[i, k] + D[k, j]);
                    }
                }
            }
        }

其中最外层循环K 表示经过K节点,i,j循环表示从i->j ,合起来的意思就是求min(dist(ij) ,dist(ik) + dist(kj)),可以看到实现很简单,时间复杂性为O(n3)

要求最远路径,只要将路径值变为相反值就行了

  int[,] dest = new int[6, 6];
            dist = new int[6, 6]{
                {0,-1,-1,0,0,0},
                {0,0,-1,0,0,0},
                {0,0,0,0,0,-1},
                {0,0,-1,0,0,0},
                {0,0,0,0,0,0},
                {0,0,0,0,0,0}
            };
  Floyd_OneNode(dist, 0, dest);
  PrintGraph_OneNode(dest, M, 0);

/// <summary>
        /// Floyd最短路径算法,求指定节点到其它节点距离
        /// </summary>
        /// <param name="dist">邻接矩阵</param>
        /// <param name="index">指定节点在邻接矩阵下标</param>
        /// <param name="D">最短路径</param>
        public static void Floyd_OneNode(int[,] dist, int index, int[,] D)
        {
            //复制一份dist
            for (int i = 0; i < M; i++)
            {
                for (int j = 0; j < M; j++)
                {
                    D[i, j] = dist[i, j];
                }
            }
            for (int k = 0; k < M; k++)
            {
                //i为指定节点
                int i = index;
                for (int j = 0; j < M; j++)
                {

                    D[i, j] = Math.Min(D[i, j], (D[i, k] == 0 || D[k, j] ==0) ? 0 : D[i, k] + D[k, j]);
                }
            }
        }

回到顶部

总结

  经过上一篇和这一篇的分析,你会发现联动问题是图论里面的相关知识,涉及到拓扑排序和最短路径算法。实际代码中还会涉及到递归,在这次开发中我感受最深的一点遇到复杂问题,一定要分析和规划清楚找到问题的本质,偏离了问题本质就可能用很复杂的代码实现了。

动态联动问题的经过总结我给出的步骤

1.计算每个节点到主节点的最远距离,(这个其实是图的最短路径的变种)。

2.找出所有最远距离是1的节点,这些节点是需要联动的,而其它最远距离不为无穷大的节点是需要清空的。

3.循环这些距离为1的节点,找这些节点直接依赖的父级节点连同主节点一起收集,传到后台进行解析。

理清楚这几个步骤你也可以实现自己的动态联动功能了!

如果,您认为阅读这篇博客让您有些收获,不妨点击一下右下角的【推荐】按钮。
如果,您希望更容易地发现我的新博客,不妨点击一下绿色通道的【关注我】。
因为,我的写作热情也离不开您的肯定支持。

感谢您的阅读,如果您对我的博客所讲述的内容有兴趣,请继续关注我的后续博客,我是焰尾迭 。

时间: 2024-08-23 10:17:28

我是怎么使用最短路径算法解决动态联动问题的的相关文章

四大算法解决最短路径问题(Dijkstra+Bellman-ford+SPFA+Floyd)

什么是最短路径问题? 简单来讲,就是用于计算一个节点到其他所有节点的最短路径. 单源最短路算法:已知起点,求到达其他点的最短路径. 常用算法:Dijkstra算法.Bellman-ford算法.SPFA算法 多源最短路算法:求任意两点之间的最短路径. 常用算法:floyd算法 单源最短路径——Dijkstra Dijkstra算法是经典的最短路径算法,用于计算一个节点到其他所有节点的最短路径. 主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止. 时间复杂度:O(n^2) 处理问题:单源.

图论(二):图的四种最短路径算法

本文总结了图的几种最短路径算法的实现:深度或广度优先搜索算法,弗洛伊德算法,迪杰斯特拉算法,Bellman-Ford算法 1),深度或广度优先搜索算法(解决单源最短路径)从起始结点开始访问所有的深度遍历路径或广度优先路径,则到达终点结点的路径有多条,取其中路径权值最短的一条则为最短路径. 下面是核心代码: void dfs(int cur, int dst){ /***operation***/ /***operation***/ if(minPath < dst) return;//当前走过路

最短路径算法小结

不同性质的图中,所采取的策略有所不同,自然存在各样的求最短路径的算法. 无向无权图:BFS 有向正权图:Dijkstra 有向无负环图:Bellman-Ford(单点),Floyd-Warshall(任意两点) 有向无环图(dags): 基于动态规划的算法. 广度优先搜索(BFS) 对于无向无权图(也可以假设权值为1),就可以使用最基本的广度优先搜索算法,从源点开始对整个图进行搜索,访问到所有的点.因为广度优先搜索最先访问到的是相邻的点,所以距离最近的点最先访问到,记录的距离也就最小. 算法伪代

基于java最短路径算法公交查询系统的设计与实现

基于J2EE的公交查询系统的设计与实现 1引言 1.1 选题背景 20多年来,我国经济得到了持续.快速.稳定.健康地发展.经济的快速增长,带动了汽车工业的蓬勃发展,并使交通状况显著改善.据统计,中国公路通车总里程已达130余万公里,其中高速公路约1.5万公里.居民收入普遍提高,到2000年年底,人均GDP已超过800美元,沿海地区已达2000-3000美元.按国际发展惯例,当人均GDP超出1000美元,汽车消费市场就将进入快速增长期.我国城市人口约有2亿,略低于美国人口.东部沿海地区大部分居民已

最短路径算法专题1----弗洛伊德

由于最短路径算法我认为比较重要,所以分成几个专题来慢慢细化去磨它,不能一口气吃个胖子嘛. 首先在说算法之前,先说清楚什么叫做最短路径. 题目一般会给你一张图,然后告诉你很多地方,然后告诉你各个地方之间的路程有多远,要你求出,两点间的最短距离,注意,题目给出的两点间的距离未必是最短的,可能通过第三个点转换之后达到更短.实际其实也是这样的,有时候两个地方并没有直线的道路只有曲线的绕路. 算法的思路: 1.用二维数组列出所有的距离,达到不了的用最大距离表示,如9999999 2.循环数组上面的每一个点

最短路径算法

最短路径-Dijkstra算法和Floyd算法 1.Dijkstra算法 1.1.定义概览Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径.主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止.Dijkstra算法是很有代表性的最短路径算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹学等等.注意该算法要求图中不存在负权边. 问题描述:在无向图 G=(V,E) 中,假设每条边 E[i] 的长度为 w[i],找到由顶点

最短路径算法整理(二)

本文是最短路径算法整理的第二篇,想阅读第一篇的朋友能够点击下面链接: http://blog.csdn.net/hjd_love_zzt/article/details/26739593 这一篇博客继续以一些OJ上的题目为载体,整理一下最短路径算法.会陆续的更新... 1.HDU 2544 题目与分析:这道题抽象一下,还是:"求a到b的最短路径"..所须要的基本条件是:点数.边数.起点.终点 下面给出floyd.dijkstra.bellmanford三种最短路径算法关于这道题的解法:

几个最短路径算法Floyd、Dijkstra、Bellman-Ford、SPFA的比较(转)

几大最短路径算法比较 几个最短路径算法的比较:Floyd        求多源.无负权边(此处错误?应该可以有负权边)的最短路.用矩阵记录图.时效性较差,时间复杂度O(V^3).       Floyd-Warshall算法(Floyd-Warshall algorithm)是解决任意两点间的最短路径的一种算法,可以正确处理有向图或负权的最短路径问题. Floyd-Warshall算法的时间复杂度为O(N^3),空间复杂度为O(N^2). Floyd-Warshall的原理是动态规划:设Di,j

(最短路径算法整理)dijkstra、floyd、bellman-ford、spfa算法模板的整理与介绍

这一篇博客以一些OJ上的题目为载体.整理一下最短路径算法.会陆续的更新... 一.多源最短路算法--floyd算法 floyd算法主要用于求随意两点间的最短路径.也成最短最短路径问题. 核心代码: /** *floyd算法 */ void floyd() { int i, j, k; for (k = 1; k <= n; ++k) {//遍历全部的中间点 for (i = 1; i <= n; ++i) {//遍历全部的起点 for (j = 1; j <= n; ++j) {//遍历