上一篇文章中有人反馈路径数值有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(路线);
}
}
}