最短経路探索アルゴリズム
経路探索アルゴリズムは日常生活で非常に一般的です。この記事では、グラフの最短経路検索アルゴリズムを実装します。
このアルゴリズムは、ゲームや屋内マップ ナビゲーションでより一般的です。
成し遂げる
例: 複数のノード間では、接続された線分の長さは固定されており、その長さが確実に通過コストになります。最小コストのパスを見つけます。グラフの構造は、
アイデア:
A>B>D と A>C>D のコストは同じであり、辺の合計は 10 に等しいことがわかります。A>C>B のルート コストは 9 に等しくなります。最短の道。
- 各ノードの子ノードをパスも含めてハッシュテーブルとして保存します。
- 関連する各ノードを再帰的にチェックしてエンドポイントに到達できるかどうかを確認し、コストを記録し、ルートし、エンドポイントまでの最後に成功したパスと比較してコストが低いパスを保存します。
- 各ノードをループするまで更新を続けます。
- 最終出力は目的の最短パスです
複雑さ: 最悪のケースは O((n-1) 2 )である必要があります。
重みを参照せずに任意の 2 点間のすべてのパスを検索します
//csharp版代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections;
namespace ConsoleApp1test
{
class Program
{
//创建图数据
static Hashtable myGraph = new Hashtable();
static void Main(string[] args)
{
//A节点及其信息与关系
myGraph["A"] = new Hashtable();
(myGraph["A"] as Hashtable)["B"] = 5;
(myGraph["A"] as Hashtable)["C"] = 2;
(myGraph["A"] as Hashtable)["F"] = 2;
//B节点
myGraph["B"] = new Hashtable();
(myGraph["B"] as Hashtable)["D"] = 5;
(myGraph["B"] as Hashtable)["F"] = 5;
//C
myGraph["C"] = new Hashtable();
(myGraph["C"] as Hashtable)["B"] = 2;
(myGraph["C"] as Hashtable)["D"] = 8;
//D
myGraph["D"] = new Hashtable();
//f
myGraph["F"] = new Hashtable();
//递归监测
GetPath(myGraph["A"] as Hashtable, "A", "D");
Console.ReadKey();
}
//创建用于存储代价的变量
static int cost = 0;
//创建用于记录路径的数据表
static Hashtable rote = new Hashtable();
static List<string> rotearray = new List<string>();
public static void GetPath(Hashtable targetNode, string startPoint, string endPoint)
{
//记录当前节点
rotearray.Add(startPoint);
Console.WriteLine("当前节点:"+ startPoint);
string st = "";
foreach (string name in rotearray)
{
st += name + ">";
}
Console.WriteLine("当前结构:"+st);
//当前节点是否是根节点
if (startPoint == endPoint)
{
//已经到达终点 //输出当前分支的每个节点
string s = "";
foreach (string name in rotearray)
{
s += name + ">";
}
Console.WriteLine("到达终点,路径:"+s);
Console.WriteLine("=================");
} else {
//未到达指定节点 遍历每个节点下相关联的子节点
foreach (string connected_node_name in targetNode.Keys)//在第一次输入时,不应该遍历所有的值
{
GetPath(myGraph[connected_node_name] as Hashtable, connected_node_name, endPoint);
}
}
//删除当前节点回 到上层
if (rotearray.Count > 0)
rotearray.RemoveAt(rotearray.Count - 1);
}
}
}
結果:
当前节点:A
当前结构:A>
当前节点:C
当前结构:A>C>
当前节点:D
当前结构:A>C>D>
到达终点,路径:A>C>D>
=================
当前节点:B
当前结构:A>C>B>
当前节点:F
当前结构:A>C>B>F>
当前节点:D
当前结构:A>C>B>D>
到达终点,路径:A>C>B>D>
=================
当前节点:F
当前结构:A>F>
当前节点:B
当前结构:A>B>
当前节点:F
当前结构:A>B>F>
当前节点:D
当前结构:A>B>D>
到达终点,路径:A>B>D>
=================
指定された 2 点間の最小 (最短) パスを検索します。
このコード部分は、重み付きグラフで最短パスを見つけてアンチループを追加するために使用され、有向グラフおよび無向グラフで使用できます。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections;
namespace ConsoleApp1test
{
class Program
{
//创建图数据
static Hashtable myGraph = new Hashtable();
static void Main(string[] args)
{
//A节点及其信息与关系
myGraph["A"] = new Hashtable();
(myGraph["A"] as Hashtable)["B"] = 5;
(myGraph["A"] as Hashtable)["C"] = 2;
(myGraph["A"] as Hashtable)["F"] = 2;
//B节点
myGraph["B"] = new Hashtable();
(myGraph["B"] as Hashtable)["D"] = 5;
(myGraph["B"] as Hashtable)["F"] = 5;
//C
myGraph["C"] = new Hashtable();
(myGraph["C"] as Hashtable)["B"] = 2;
(myGraph["C"] as Hashtable)["D"] = 8;
//D
myGraph["D"] = new Hashtable();
//f
myGraph["F"] = new Hashtable();
(myGraph["F"] as Hashtable)["B"] = 2;
//递归监测
GetPath(myGraph["A"] as Hashtable, "A", "D");
Console.WriteLine("最短路径:" + shortestPath + " 代价:" + shortestCost + "米");
Console.ReadKey();
}
//创建用于存储代价\记录路径的数据表
static List<string> pathList = new List<string>();
static List<int> pathCostList = new List<int>();
static int shortestCost = 100000;
static string shortestPath = "";
public static void GetPath(Hashtable targetNode, string startPoint, string endPoint)
{
//记录当前节点
pathList.Add(startPoint);
Console.WriteLine("当前节点:"+ startPoint);
string allPath = "";
for(int i=0; i < pathList.Count; i++)
{
allPath += pathList[i];
allPath += (i == (pathList.Count - 1)) ? "" : ">";
}
Console.WriteLine("当前结构:" + allPath);
//当前节点是否是根节点
if (startPoint == endPoint)
{
//已经到达终点 //输出当前分支的每个节点
Console.WriteLine("到达终点,路径:"+ allPath);
//计算所有的权值
int pathCost_total = 0;
foreach (int pathCost in pathCostList)
{
pathCost_total += pathCost;
}
Console.WriteLine("代价:" + pathCost_total.ToString() + "米");
//更新最短路径信息
if (pathCost_total < shortestCost) {
shortestCost = pathCost_total;
shortestPath = allPath;
}
Console.WriteLine("==========害羞而淫荡的分割线==========");
} else {
//未到达指定节点 遍历每个节点下相关联的子节点
foreach (string connected_node_name in targetNode.Keys)
{
//如果,路径中已存在节点,就不走了。 避免循环。
if (!pathList.Contains(connected_node_name)) {
//记录路径权值
pathCostList.Add((int)targetNode[connected_node_name]);
GetPath(myGraph[connected_node_name] as Hashtable, connected_node_name, endPoint);
//记录路径权值
if (pathCostList.Count > 0)
pathCostList.RemoveAt(pathCostList.Count - 1);
}
}
}
//删除当前节点回 到上层
if (pathList.Count > 0)
pathList.RemoveAt(pathList.Count - 1);
}
}
}
結果:
当前节点:A
当前结构:A
当前节点:C
当前结构:A>C
当前节点:D
当前结构:A>C>D
到达终点,路径:A>C>D
代价:10米
==========害羞而淫荡的分割线==========
当前节点:B
当前结构:A>C>B
当前节点:F
当前结构:A>C>B>F
当前节点:D
当前结构:A>C>B>D
到达终点,路径:A>C>B>D
代价:9米
==========害羞而淫荡的分割线==========
当前节点:F
当前结构:A>F
当前节点:B
当前结构:A>F>B
当前节点:D
当前结构:A>F>B>D
到达终点,路径:A>F>B>D
代价:9米
==========害羞而淫荡的分割线==========
当前节点:B
当前结构:A>B
当前节点:F
当前结构:A>B>F
当前节点:D
当前结构:A>B>D
到达终点,路径:A>B>D
代价:10米
==========害羞而淫荡的分割线==========
最短路径:A>C>B>D 代价:9米
重み付きグラフでは、理論上、重みを等しいノードに変換でき、最短ノード アルゴリズムを使用して最短パスを見つけることもできます。