惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

云风的 BLOG
云风的 BLOG
C
Cyber Attacks, Cyber Crime and Cyber Security
Recent Announcements
Recent Announcements
爱范儿
爱范儿
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Security Latest
Security Latest
J
Java Code Geeks
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Cisco Talos Blog
Cisco Talos Blog
Apple Machine Learning Research
Apple Machine Learning Research
C
Check Point Blog
T
Threat Research - Cisco Blogs
I
Intezer
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
WordPress大学
WordPress大学
Engineering at Meta
Engineering at Meta
腾讯CDC
Google DeepMind News
Google DeepMind News
Project Zero
Project Zero
T
Tenable Blog
V
Visual Studio Blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
Spread Privacy
Spread Privacy
GbyAI
GbyAI
T
Tailwind CSS Blog
P
Palo Alto Networks Blog
Microsoft Security Blog
Microsoft Security Blog
Scott Helme
Scott Helme
Hugging Face - Blog
Hugging Face - Blog
NISL@THU
NISL@THU
Blog — PlanetScale
Blog — PlanetScale
G
GRAHAM CLULEY
K
Kaspersky official blog
T
The Exploit Database - CXSecurity.com
S
Schneier on Security
P
Proofpoint News Feed
S
SegmentFault 最新的问题
P
Proofpoint News Feed
P
Privacy & Cybersecurity Law Blog
The Hacker News
The Hacker News
博客园 - 【当耐特】
Cyberwarzone
Cyberwarzone
L
LangChain Blog
Stack Overflow Blog
Stack Overflow Blog
V
Vulnerabilities – Threatpost
H
Help Net Security
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Last Week in AI
Last Week in AI
博客园 - 叶小钗

博客园 - HotSky

Chrome启用CDP(chrome-devtools-protocol)进行远程操控 WPF 让ScrollViewer支持按住鼠标中键拖拽滚动内容 WPF 让ScrollViewer支持鼠标中键滚动缩放内容 Nodejs使用 nodejs中写sql需要用in时的写法 C#Animation Sqlite PDF附录A: 内容流操作码 WPF FPS类 生命模拟 C# Sql帮助类,可扩展 WPF WriteableBitmap通过GDI+绘制帮助类 Alpha混合 Bmp读写二值图 WPF支持任意快捷键+鼠标组合的绑定类 WPF阻止窗体被系统缩放,使用显示器DPI WPF DataGrid自动增长序号列 C#访问或修改私有类、函数、变量、属性 WPF一个简单的属性编辑控件
C#城市最短路径
HotSky · 2025-05-09 · via 博客园 - HotSky

123

public class City
{
    public int Id { get; set; }
    public string Name { get; set; }

    public List<City> Cities { get; set; } = new List<City>();
    public List<Road> Roads { get; set; } = new List<Road>();
}
/// <summary>
/// 城市之间的道路
/// </summary>
public class Road
{
    public int Id { get; set; }
    public int City1 { get; set; }
    public int City2 { get; set; }
    public int Days { get; set; }
}
public class CityGraph
{
    public List<City> Cities { get; set; } = new List<City>();
    public List<Road> Roads { get; set; } = new List<Road>();

    public void AddRoad(string c1, string c2, int days = 1)
    {
        AddRoad(Cities.Find(x => x.Name == c1), Cities.Find(x => x.Name == c2), days);
    }
    public void AddRoad(City city1, City city2, int days)
    {
        if(Roads.Exists(x => (x.City1 == city1.Id && x.City2 == city2.Id) || (x.City1 == city2.Id && x.City2 == city1.Id)))
            return;
        var r = new Road { City1 = city1.Id, City2 = city2.Id, Days = days };
        Roads.Add(r);
        city1.Roads.Add(r);
        city2.Roads.Add(r);
        city1.Cities.Add(city2);
        city2.Cities.Add(city1);
    }
    
    /// <summary>
    /// 查找两座城市之间的最短路径
    /// </summary>
    /// <param name="city1"></param>
    /// <param name="city2"></param>
    /// <returns></returns>
    public List<City> FindShortRoads(City city1, City city2)
    {
        //以起点城市为根节点,构建城市树
        //查找所有到达终点城市的路径
        //遍历所有路径,计算路径的深度
        //返回最小深度的路径
        CityNode root = new CityNode { Id = city1.Id };
        Tree(root);
        var list = root.FindNode(city2.Id);
        if (list.Count == 0)
            return null;
        // 计算最小深度
        int min = list.Min(x => x.Depth());
        var node = list.Find(f => f.Depth() == min);
        var result = new List<City>();
        do
        {
            result.Insert(0, Cities.Find(x => x.Id == node.Id));
            node = node.Parent;
        } while (node != null);
        return result;
    }

    /// <summary>
    /// 构建城市树
    /// </summary>
    /// <param name="node"></param>
    public void Tree(CityNode node)
    {
        var city = Cities.Find(x => x.Id == node.Id);
        foreach (var item in city.Cities)
        {
            if (!node.EqualParent(item.Id))
            {
                var road = Roads.Find(x => (x.City1 == node.Id && x.City2 == item.Id) || (x.City1 == item.Id && x.City2 == node.Id));
                node.AddChild(new CityNode { Id = item.Id, Days = road.Days });
            }
        }
        foreach (var item in node.Nodes)
        {
            Tree(item);
        }
    }
}

public class CityNode
{
    public int Id { get; set; }
    public int Days { get; set; }
    public CityNode Parent { get; set; }
    public List<CityNode> Nodes { get; set; } = new List<CityNode>();

    public void AddChild(CityNode node)
    {
        if (Nodes.Exists(x => x.Id == node.Id))
            return;
        Nodes.Add(node);
        node.Parent = this;
    }
    public void RemoveChild(CityNode node)
    {
        if (!Nodes.Exists(x => x.Id == node.Id))
            return;
        Nodes.Remove(node);
        if (node.Parent == this)
            node.Parent = null;
    }

    /// <summary>
    /// 判断父节点是否是指定的节点
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public bool EqualParent(int id)
    {
        if (Parent == null)
            return false;
        if (Parent.Id == id)
            return true;
        return Parent.EqualParent(id);
    }

    /// <summary>
    /// 计算深度
    /// </summary>
    /// <returns></returns>
    public int Depth()
    {
        if (Parent == null)
            return Days;
        return Parent.Depth() + Days;
    }

    /// <summary>
    /// 查找指定节点
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public List<CityNode> FindNode(int id)
    {
        if (Id == id)
            return new List<CityNode> { this };
        List<CityNode> list = new List<CityNode>();
        foreach (var item in Nodes)
        {
            var l = item.FindNode(id);
            if (l.Count > 0)
                list.AddRange(l);
        }
        return list;
    }
}

示例:

CityGraph cityGraph = new CityGraph();

#region Data
string s = "ABCDEFGHIJKLMNOPQRST";
for (int i = 0; i < s.Length; i++)
    cityGraph.Cities.Add(new City { Id = i + 1, Name = s[i].ToString() });
cityGraph.AddRoad("A", "B");
cityGraph.AddRoad("A", "H");
cityGraph.AddRoad("A", "G");
cityGraph.AddRoad("B", "C");
cityGraph.AddRoad("B", "J");
cityGraph.AddRoad("B", "I");
cityGraph.AddRoad("B", "H");
cityGraph.AddRoad("H", "I");
cityGraph.AddRoad("H", "P");
cityGraph.AddRoad("H", "G");
cityGraph.AddRoad("G", "P");
cityGraph.AddRoad("G", "O");
cityGraph.AddRoad("C", "D");
cityGraph.AddRoad("C", "J");
cityGraph.AddRoad("J", "D");
cityGraph.AddRoad("J", "K");
cityGraph.AddRoad("J", "I");
cityGraph.AddRoad("I", "R");
cityGraph.AddRoad("I", "Q");
cityGraph.AddRoad("I", "P");
cityGraph.AddRoad("P", "O");
cityGraph.AddRoad("D", "E");
cityGraph.AddRoad("D", "M");
cityGraph.AddRoad("D", "K");
cityGraph.AddRoad("K", "M");
cityGraph.AddRoad("K", "L");
cityGraph.AddRoad("K", "R");
cityGraph.AddRoad("R", "L");
cityGraph.AddRoad("R", "L");
cityGraph.AddRoad("R", "S");
cityGraph.AddRoad("R", "Q");
cityGraph.AddRoad("E", "F");
cityGraph.AddRoad("E", "M");
cityGraph.AddRoad("M", "F");
cityGraph.AddRoad("M", "N");
cityGraph.AddRoad("M", "L");
cityGraph.AddRoad("L", "N");
cityGraph.AddRoad("L", "T");
cityGraph.AddRoad("L", "S");
cityGraph.AddRoad("S", "T");
cityGraph.AddRoad("N", "T");
#endregion

Random random = new Random();
foreach (var item in cityGraph.Roads)
{
    item.Days = random.Next(1, 10);
}
var list = cityGraph.FindShortRoads(cityGraph.Cities[0], cityGraph.Cities.Last());
Debug.WriteLine(list.Select(x => x.Name).Aggregate((x, y) => x + "->" + y));