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

上一篇文章中有人反馈路径数值有bug,我对此进行了更改与修复,大家看着理解吧,我还有事要忙,就不进行讲解了,另外在此感谢小伙伴的反馈,之前没认真做测试实在抱歉。

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)
        {
            //定义网络结构
            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;
            List<string> 中转站 = new List<string>();
            List<int> 中转站路线长 = new List<int>();
            int 指针 = 0;
            中转站.Add("D");//"B", "C", "D", "E", "F"都可测试
            while (true)
            {
                
                //创建集合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 (mListptU[mini] == 中转站[指针])
                    {

                        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)

                        {
                            //筛选可合并的路线
                            //如果通过中间点到达比直接到达更快(没有直达路线的可以认为原来是有一条无限长的直达路线)
                            //不要和我说两边之和一定大于第三边的逻辑,计算机里面不是这么玩的,那个东西叫权值,便于理解我才说的路径
                            //MessageBox.Show(mListptU[i] + updatedis.ToString());
                            if (mListptDisU[i] > updatedis + intDis[i, updateindex])
                            {
                                //MessageBox.Show();

                                if (mListptU[i] == 中转站[指针])
                                {
                                    中转站.Add(updatept);

                                    指针++;
                                }
                                //则让最短路径长度为带有中转站的点的总路径长
                                mListptDisU[i] = intDis[i, updateindex] + updatedis;
                            }
                        }
                    }
                    //循环每运行一次相当于给A添加几班直达车(比之前所有到达路径更短的直达车),到达可已通过updatept到达的点
                    //需要注意的是如果通过该点到达比直达(或之前添加的直达车)慢,则不会再添加直达车
                    //此时可认为该点消失
                    //直到A到任意一点都有最短直达车,循环结束(所有点都消失了)

                }
            }

        //那么问题来了,这种方法只能统计A到所有点的最短路径,无法记录它是怎么走的该如何是好?
        //我在这里采用了回溯算法,即在已知结果的情况下不断回溯得到答案,不细说自己悟,
        //使用中文命名是因为我懒得写注释了
        over:;
            int k = 0;
            int[] temp = new int[中转站.Count+1];
            
            while (k< 中转站.Count) { 
                for(int j = 0; j < str.Length; j++)
                {
                    if(str[j]== 中转站[k])
                    {
                        temp[k++] = j;
                        break;
                    }
                    
                }
            }
            temp[中转站.Count] = 0;
            for(int i = 0; i < temp.Length-1; i++)
            {
                中转站路线长.Add(intDis[temp[i], temp[i + 1]]);
            }
            
            String 路线 = "A";
            for (int i = 中转站.Count - 1; i >= 0; i--)
            {
                路线 += "--"+中转站路线长[i] + "->"+ 中转站[i];
            }
            MessageBox.Show(路线);
            }
    }
}

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值