我目前有两个4个3D点列表,让我们调用列表A和B.我想将A中的每个点连接到B中的一个(并且只有一个)点,以便A和B之间的总距离最小化。
例如,如果我有:
一个 1:(0,0,0) 2:(0,10,0) 3:(0,20,0) 4:(0,30,0)
乙 1:(0,35,10) 2:(0,25,10) 3:(0,15,10) 4:(0,5,10)
最佳解决方案是将A1与B4连接,A2与B3连接,A3与B2连接,A4与B1连接。
我如何以合理的方式计算这个?
答案 0 :(得分:4)
当项目数量很小时,就像你的情况一样,你可以通过在三个嵌套循环中强制执行所有排列来实现这一点:
Point3D[] a = new Point3D[4];
Point3D[] b = new Point3D[4];
for (int i = 0 ; i != 4 ; i++) {
for (int j = 0 ; j != 4 ; j++) {
if (j == i) continue;
for (int k = 0 ; k != 4 ; k++) {
int m = 6 - i - j - k;
if (k == i || k == j || m == i || m == j || m == k) continue;
var d = a[0].Distance(b[i]) +a[1].Distance(b[j]) + a[2].Distance(b[k]) + a[3].Distance(b[m]);
min = Math.Min(d, min);
}
}
}
这可以找到4的最小值! = 24次迭代。如果你有更多的点,比如说超过10个,那么可以使用更好的算法 - 你可以使用Hungerian algorithm在多项式时间 O中找到最小权重匹配(n 3 < / SUP>)
答案 1 :(得分:0)
public static IEnumerable<Result> Connect(this IEnumerable<Point> setA, IEnumerable<Point> setB) {
return setA
.Select(a => setB.Select(b => new Result { A = a, B = b, D = a.DistanceTo(b) }))
.SelectMany(s => s)
.OrderBy(s => s.D)
.Reduce(new Result[] { }, (a,b) => a.A != b.A && a.B != b.B);
}
使用:
public static IEnumerable<T> Concat<T>(this T h, IEnumerable<T> t) {
yield return h;
foreach (var r in t) {
yield return r;
}
}
static IEnumerable<T> Reduce<T>(this IEnumerable<T> items, IEnumerable<T> collected, Func<T,T,bool> predicate) {
if (!items.Any())
return new T[0];
var t = items.First();
var filtered = items.Where(s => predicate(s,t));
return t.Concat(filtered.Reduce(t.Concat(collected), predicate));
}
,其中
struct Result {
public Point A;
public Point B;
public double D;//distance
}
struct Point {
public int X;
public int Y;
public int Z;
}
double DistanceTo(this Point a, Point b) {
return Math.Sqrt((a.X - b.X) * (a.X - b.X) + (a.Y - b.Y) * (a.Y - b.Y) + (a.Z - b.Z) * (a.Z - b.Z));
}