Поиск ближайшей точки
Спасибо вам за задачку. Очень она меня заинтересовала.

Набросал на коленке один алгоритм, реализация на C# работает довольно сносно: ~4.5 сек на моей дряхлой машине. Если грамотно распараллелить (а это должно быть довольно просто для данного алгоритма), то должно быть еще быстрее.
Единственное отличие от вашей постановки задачи: координаты точек я задавал типом double, а не float.

Суть алгоритма: перейти к целым числам в том смысле, что накрыть ОДЗ (-10 000 < x,y,z < 10 000) трехмерной сеткой.
Для случая равномерного распределения точек — проще всего равномерной же сеткой.
Эксперименты показали, что оптимальный шаг сетки для указанных в условии задачи параметров лежит в диапазоне 100-400, но это не принципиально.
Необходимо разложить все точки одного цвета (пусть это будет красный) по ячейкам. Лично я решил раскладывать не сами точки, а их индексы в исходном массиве. Это легко сделать, особенно в равномерном случае. То есть, выражаясь языком C#, заполняется такой трехмерный массив: List<int>[,,] gridЭлементами этого массива являются списки индексов красных точек, попадающих в соответствующую ячейку.

Далее нам придется сделать такую штуку, которую я называю «сферическим циклом» (не знаю, появилось ли какое-то стандартное наименование для таких конструкций). Суть такого цикла можно объяснить на пальцах так: обходим ячейки сетки, начиная с некоторой начальной тройки индексов i0, j0, k0, и далее расходясь концентрическими сферами. Иными словами, сначала цикл попадает в начальную ячейку, затем пробегает все ячейки, отстоящие от начальной на 1 (округленно), потом на 2 (округленно) и т.д.

Далее, в самом обычном цикле пробегаем все черные точки, вызывая для каждой из них этот самый «сферический цикл», в котором и ищем ближайшего соседа. Правда там есть еще хитрость с условием выхода из этого цикла, но это мелочи.

Есть исходник на C#. Если есть интерес, могу его предоставить.
Самый простой способ — перебором:
var sqr = function(x) { return x * x; };
var summ = 0;
for (var i in red_points)
{
  var minSLen = false;
  for (var j in black_points)
  {
    var sLen = sqr(black_points[j].x - red_points[i].x) + sqr(black_points[j].y - red_points[i].y) + sqr(black_points[j].z - red_points[i].z);
    if (minSLen === false || sLen < minSLen)
      minSLen = sLen;
  }
  if (minSLen >= 0)
    summ += Math.sqrt(minSLen);
}

Эффективность у него довольно низкая, но зато работает в любых условиях :-)