|
|
using WpfNodeTest.Models;
|
|
|
|
|
|
namespace WpfNodeTest.Services;
|
|
|
|
|
|
/// <summary>
|
|
|
/// 路径规划服务(使用Dijkstra算法)
|
|
|
/// </summary>
|
|
|
public class PathPlanningService
|
|
|
{
|
|
|
/// <summary>
|
|
|
/// 规划从起点到终点的路径
|
|
|
/// </summary>
|
|
|
/// <param name="graphData">节点图数据</param>
|
|
|
/// <param name="startNodeId">起点节点ID</param>
|
|
|
/// <param name="endNodeId">终点节点ID</param>
|
|
|
/// <returns>路径节点ID列表</returns>
|
|
|
public List<string> PlanPath(NodeGraphData graphData, string startNodeId, string endNodeId)
|
|
|
{
|
|
|
// 构建邻接表(双向图)
|
|
|
var adjacency = BuildAdjacency(graphData);
|
|
|
|
|
|
// Dijkstra算法
|
|
|
var distances = new Dictionary<string, double>();
|
|
|
var previous = new Dictionary<string, string>();
|
|
|
var unvisited = new HashSet<string>();
|
|
|
|
|
|
foreach (var node in graphData.Nodes)
|
|
|
{
|
|
|
distances[node.Id] = double.MaxValue;
|
|
|
unvisited.Add(node.Id);
|
|
|
}
|
|
|
distances[startNodeId] = 0;
|
|
|
|
|
|
while (unvisited.Count > 0)
|
|
|
{
|
|
|
var current = unvisited.OrderBy(n => distances[n]).First();
|
|
|
unvisited.Remove(current);
|
|
|
|
|
|
if (current == endNodeId) break;
|
|
|
|
|
|
if (adjacency.TryGetValue(current, out var neighbors))
|
|
|
{
|
|
|
foreach (var (neighbor, weight) in neighbors)
|
|
|
{
|
|
|
if (!unvisited.Contains(neighbor)) continue;
|
|
|
|
|
|
var alt = distances[current] + weight;
|
|
|
if (alt < distances[neighbor])
|
|
|
{
|
|
|
distances[neighbor] = alt;
|
|
|
previous[neighbor] = current;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 回溯路径
|
|
|
var path = new List<string>();
|
|
|
var step = endNodeId;
|
|
|
while (previous.ContainsKey(step))
|
|
|
{
|
|
|
path.Add(step);
|
|
|
step = previous[step];
|
|
|
}
|
|
|
path.Add(startNodeId);
|
|
|
path.Reverse();
|
|
|
|
|
|
return path;
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 构建邻接表(双向图)
|
|
|
/// </summary>
|
|
|
private Dictionary<string, List<(string nodeId, double weight)>> BuildAdjacency(NodeGraphData graphData)
|
|
|
{
|
|
|
var adjacency = new Dictionary<string, List<(string, double)>>();
|
|
|
|
|
|
foreach (var node in graphData.Nodes)
|
|
|
{
|
|
|
adjacency[node.Id] = new List<(string, double)>();
|
|
|
}
|
|
|
|
|
|
foreach (var conn in graphData.Connections)
|
|
|
{
|
|
|
// 双向连接
|
|
|
adjacency[conn.SourceNodeId].Add((conn.TargetNodeId, conn.Weight));
|
|
|
adjacency[conn.TargetNodeId].Add((conn.SourceNodeId, conn.Weight));
|
|
|
}
|
|
|
|
|
|
return adjacency;
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 将路径拆分为子任务
|
|
|
/// </summary>
|
|
|
/// <param name="path">路径节点ID列表</param>
|
|
|
/// <param name="graphData">节点图数据</param>
|
|
|
/// <returns>子任务列表(起点->终点)</returns>
|
|
|
public List<(string from, string to)> SplitToSubTasks(List<string> path, NodeGraphData graphData)
|
|
|
{
|
|
|
var subTasks = new List<(string, string)>();
|
|
|
|
|
|
for (int i = 0; i < path.Count - 1; i++)
|
|
|
{
|
|
|
subTasks.Add((path[i], path[i + 1]));
|
|
|
}
|
|
|
|
|
|
return subTasks;
|
|
|
}
|
|
|
} |