C#Dijkstra(迪杰斯特拉)求算法最短路线,以及使用回溯算法寻找路径

  

文章中的路线没问题但是路线数值有bug,请移步:C#Dijkstra(迪杰斯特拉)求算法最短路线,以及使用回溯算法寻找路径(bug修复)_星空的你的博客-CSDN博客

 讲解都在代码段中可谓是非常详细了,回溯算法没细说因为很简单,扫一眼就知道是怎么回事了

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApp9
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            List<string> 中转站 = new List<string>();
            List<int> 中转站路线长 = new List<int>();
            int 指针 = 0;
            中转站.Add("B");//"B", "C", "D", "E", "F"都可测试
            while (true)
            {
                //从这里开始,外层while是回溯算法的需要
                //定义网络结构
                string[] str = { "A", "B", "C", "D", "E", "F" };
                int[,] intDis = new int[7, 7];
                //建图初始路径长度为无穷大(一般用一个很大的值来代替,这里为10000)
                for (int i = 0; i < 7; i++)
                {
                    for (int j = 0; j < 7; j++)
                    {
                        intDis[i, j] = 10000;
                    }

                }
                //绘图,给每两个点之间建立路径,没有建立为无穷大即不可到达
                intDis[0, 1] = intDis[1, 0] = 8;
                intDis[1, 2] = intDis[2, 1] = 9;
                intDis[2, 3] = intDis[3, 2] = 5;
                intDis[3, 4] = intDis[4, 3] = 4;
                intDis[2, 4] = intDis[4, 2] = 3;
                intDis[0, 4] = intDis[4, 0] = 4;
                intDis[0, 5] = intDis[5, 0] = 5;
                intDis[2, 5] = intDis[5, 2] = 5;
                intDis[4, 5] = intDis[5, 4] = 6;
                intDis[1, 5] = intDis[5, 1] = 7;
                //创建集合S(已吞并点的集合)、U(未吞并点的集合)
                List<string> mListptS = new List<string>();//存点
                List<int> mListptDisS = new List<int>();//存权值(即路径长度)
                List<string> mListptU = new List<string>();
                List<int> mListptDisU = new List<int>();
                //S
                mListptS.Add("A");
                mListptDisS.Add(0);
                //U
                mListptU.Add("E");
                mListptDisU.Add(4);
                mListptU.Add("F");
                mListptDisU.Add(5);
                mListptU.Add("B");
                mListptDisU.Add(8);
                mListptU.Add("C");
                mListptDisU.Add(10000);
                mListptU.Add("D");
                mListptDisU.Add(10000);
                
            
            
                //距离计算
                while (mListptDisU.Count > 0)
                {
                    int mindis = 10000;
                    int mini = 0;
                    //在集合U中寻找可到达的点中路径最短的点,并记录点在集合U中的下标和与A点间的距离
                    for (int i = 0; i < mListptU.Count; i++)
                    {
                        if (mindis > mListptDisU[i])
                        {
                            mindis = mListptDisU[i];
                            mini = i;
                        }
                    }
                    
                    
                    //将找到的点添加进集合S中
                    mListptS.Add(mListptU[mini]);//加点
                    mListptDisS.Add(mListptDisU[mini]);//加路径

                    string updatept = mListptU[mini];//点
                    int updateindex = 0;
                    //在最上方str数组中寻找此点的下标并记录
                    for (int i = 0; i < 6; i++)
                    {
                        if (updatept == str[i])
                        {
                            updateindex = i;
                            break;
                        }
                    }
                    int updatedis = mListptDisU[mini];//路径
                    //这个if回溯算法的出口,先不用看
                    if (mListptU[mini] == 中转站[指针])
                    {
                        中转站路线长.Add(updatedis);
                        goto over;
                    }
                    //移除U中该点和对应路径
                    mListptDisU.Remove(mListptDisU[mini]);
                    mListptU.Remove(mListptU[mini]);
                    //MessageBox.Show(mListptU[mini]);
                    //MessageBox.Show(中转站[指针]);
                    
                    //开始合并路线
                    for (int i = 0; i < mListptU.Count; i++)
                    {
                        //筛选可通过当前updatept到达的点
                        if (intDis[i, updateindex] < 10000 || intDis[updateindex, i] < 10000)
                        {
                            //筛选可合并的路线
                            //如果通过中间点到达比直接到达更快(没有直达路线的可以认为原来是有一条无限长的直达路线)
                            //不要和我说两边之和一定大于第三边的逻辑,计算机里面不是这么玩的,那个东西叫权值,便于理解我才说的路径
                            if (mListptDisU[i] > updatedis + intDis[i, updateindex])
                            {
                                //MessageBox.Show(mListptU[i]);
                                //MessageBox.Show(中转站[指针]);
                                //此if也是回溯算法的需要,先不用看
                                if (mListptU[i] == 中转站[指针])
                                {
                                    中转站.Add(updatept);
                                    中转站路线长.Add(updatedis);
                                    指针++;
                                }
                                //则让最短路径长度为带有中转站的点的总路径长
                                mListptDisU[i] = intDis[i, updateindex] + updatedis;
                            }
                        }
                    }
                    //循环每运行一次相当于给A添加几班直达车(比之前所有到达路径更短的直达车),到达可已通过updatept到达的点
                    //需要注意的是如果通过该点到达比直达(或之前添加的直达车)慢,则不会再添加直达车
                    //此时可认为该点消失
                    //直到A到任意一点都有最短直达车,循环结束(所有点都消失了)

                }
            }

        //那么问题来了,这种方法只能统计A到所有点的最短路径,无法记录它是怎么走的该如何是好?
        //我在这里采用了回溯算法,即在已知结果的情况下不断回溯得到答案,不细说自己悟,
        //使用中文命名是因为我懒得写注释了,也方便与其他代码做区分
        over:;

        String 路线 = "A";
        for (int i = 中转站.Count - 1; i >= 0; i--)
        {
            路线 += "--"+中转站路线长[i] + "->"+ 中转站[i];
        }
        MessageBox.Show(路线);
        }
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值