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

推荐订阅源

WordPress大学
WordPress大学
Engineering at Meta
Engineering at Meta
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Martin Fowler
Martin Fowler
雷峰网
雷峰网
Recent Announcements
Recent Announcements
博客园 - 叶小钗
F
Full Disclosure
C
Check Point Blog
A
About on SuperTechFans
L
LangChain Blog
Vercel News
Vercel News
T
The Blog of Author Tim Ferriss
博客园 - 司徒正美
C
Cybersecurity and Infrastructure Security Agency CISA
C
CXSECURITY Database RSS Feed - CXSecurity.com
Cisco Talos Blog
Cisco Talos Blog
Hugging Face - Blog
Hugging Face - Blog
Recorded Future
Recorded Future
MongoDB | Blog
MongoDB | Blog
Project Zero
Project Zero
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Know Your Adversary
Know Your Adversary
D
Docker
U
Unit 42
酷 壳 – CoolShell
酷 壳 – CoolShell
T
The Exploit Database - CXSecurity.com
L
Lohrmann on Cybersecurity
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Latest news
Latest news
V
Visual Studio Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
L
LINUX DO - 最新话题
Google DeepMind News
Google DeepMind News
小众软件
小众软件
NISL@THU
NISL@THU
GbyAI
GbyAI
H
Heimdal Security Blog
Jina AI
Jina AI
I
InfoQ
PCI Perspectives
PCI Perspectives
P
Privacy International News Feed
P
Proofpoint News Feed
N
News and Events Feed by Topic
C
CERT Recently Published Vulnerability Notes
aimingoo的专栏
aimingoo的专栏
SecWiki News
SecWiki News
B
Blog RSS Feed
阮一峰的网络日志
阮一峰的网络日志

博客园 - 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));