适用于闭环状态下各节点间距相等,计算从其中一个节点去1个或多个目标节点的最短路径,最短路径可以折返取得。
下面是一个有着10000个节点的闭环,从其中一个节点去往9个目标节点的示例。
static void Main(string[] args)
{
int x = 3;//起点
int[] arr = { 2, 2000, 4900, 9990, 6001, 200, 400, 80, 60 };//目的地
int pe = 10000;//全周总步进
int[] pathArr = ShortestPath(x, arr, pe);
Console.WriteLine(string.Join(",",pathArr));
}
static int[] ShortestPath(int x, int[] goalArr, int perim)
{
List<int> aList = goalArr.Where(p => p != x && p >= 1 && p <= perim).ToList();
if (!aList.Any()) return null;
//最大折返步进数(折返步进数的3倍小于等于1/2总周步进,折返才可能存在最优路径。)
int bl = (int)Math.Floor(perim / 6m);
int a = x;
int b = x;
int c = x - bl < 1 ? perim + x - bl : x - bl;
int d = x + bl > perim ? x + bl - perim : x + bl;
IEnumerable<int> aIE = new int[] { x };
IEnumerable<int> bIE = new int[] { x };
IEnumerable<int> cIE = new int[] { };
IEnumerable<int> dIE = new int[] { };
//如在双向最大折返步进内存在目的地,取双向最远折返点到起点之间的步进
for (int i = 0; i < bl ; i++)
{
if (cIE.Any() || aList.Contains(c)) cIE = (new int[] { c }).Concat(cIE);
if (dIE.Any() || aList.Contains(d)) dIE = (new int[] { d }).Concat(dIE);
c = c + 1 > perim ? 1 : c + 1;
d = d - 1 < 1 ? perim : d - 1;
}
cIE = (new int[] { x }).Concat(cIE);
dIE = (new int[] { x }).Concat(dIE);
c = cIE.Last();
d = dIE.Last();
List<int> cList = aList.Where(p => !cIE.Contains(p)).ToList();
if (!cList.Any()) return cIE.ToArray();
List<int> dList = aList.Where(p => !dIE.Contains(p)).ToList();
if (!dList.Any()) return dIE.ToArray();
List<int> bList = aList.GetRange(0, aList.Count);
for (int i = 1; i < perim; i++)
{
a = a + 1 > perim ? 1 : a + 1;
b = b - 1 < 1 ? perim : b - 1;
c = c + 1 > perim ? 1 : c + 1;
d = d - 1 < 1 ? perim : d - 1;
aIE = aIE.Concat(new int[] { a });
if (aList.Contains(a))
{
aList.Remove(a);
if (!aList.Any()) return aIE.ToArray();
}
bIE = bIE.Concat(new int[] { b });
if (bList.Contains(b))
{
bList.Remove(b);
if (!bList.Any()) return bIE.ToArray();
}
if (cList.Any()) cIE = cIE.Concat(new int[] { c });
if (cList.Contains(c)) cList.Remove(c);
if (!cList.Any() && cIE.Count() < dIE.Count()) return cIE.ToArray();
if (dList.Any()) dIE = dIE.Concat(new int[] { d });
if (dList.Contains(d)) dList.Remove(d);
if (!dList.Any() && dIE.Count() < cIE.Count()) return dIE.ToArray();
}
return null;
}