算法:如何将固定长度圆形阵列中的新元素尽可能远离现有元素?

时间:2015-01-16 19:30:20

标签: algorithm

我希望尽可能远离彼此。

假设数组的长度为360.

Element 1 goes at position 0.
Element 2 goes at position 180.
Element 3 goes at position 90 (or 270).
Element 4 goes at position 270 (or 90).
Element 5 goes at position 45.
Element 6 goes at position 135.
Element 7 goes at position 225.
Element 8 goes at position 315.
Element 9 goes at position 23.
Element 10 goes at position 68.

等等。

我们说长度是100。

Element 1 goes at position 0.
Element 2 goes at position 50.
Element 3 goes at position 25 (or 75).
Element 4 goes at position 75 (or 72).
Element 5 goes at position 13.
Element 6 goes at position 38 (or 75).
Element 7 goes at position 63.

等等。

用户将传入数组长度和元素编号。所以f(2,360)将返回180而f(7,100)将返回63。

给定数组长度和元素编号输出位置的方法是什么?

编辑:我的具体应用是,在我知道将会有多少元素之前,我试图为每个元素选择不同色调的颜色,等间距。

编辑2:我的问题陈述造成了一些混乱。为简单起见,我在演示解决方案中使用了整数,当时我并不想要整数输出。我的错。我会将解决这个问题的解决方案标记为正确,但我应该警告我自己没有检查过。我的答案在下面我已经检查过并且有效,尽管它是0索引并返回小数。

3 个答案:

答案 0 :(得分:2)

菲尔的解决方案让我思考。我认为这稍微好一点,因为它只需要一个日志。在JavaScript中:

// Returns the position of element n
// as far away as possible from other elements
// with total space totalSpace
function getPlacement(n, totalSpace) {
    if (n == 0) return 0;

    var divisions = Math.pow(2, log2Floor(n) + 1);
    var position = ((2 * (n + 1 - (divisions / 2))) - 1);
    return position * ( totalSpace / divisions );
}

// Quickly returns the floor of the base 2 log
function log2Floor(x) {
  if (x === 0) return -Infinity;
  for (var i = 0; i < 32; ++i) {
    if (x >>> i === 1) return i;
  }
}

答案 1 :(得分:0)

您正在寻找的这个函数,我们称之为f(i,n),可以按如下方式递归定义(假设索引从0开始,log(x)输出{{1}的基数2对数的下限}}):

x

希望这有帮助!

答案 2 :(得分:0)

只要0 < i <= n,这是一个不重复的非递归解决方案。它是尽可能以语言无关的方式编写的,所以如果你不了解ruby它应该无关紧要:

# round, but if fraction is .5 then floor.
def round2 x
  double = 2*x
  double == double.round ? x.floor : x.round
end

# i is 1-based. 0 < n.
def f( i, n )
  j = (i-1) % n # convert to 0-based and mod n index j
  nsig = 1 << Math.log2(n).floor # highest bit in n
  if (j&nsig) == 0
    j2 = 1 << Math.log2((j<<1)|1).floor # smallest power of 2 > j
    angle = n*(j2^((j<<1)|1)) / j2.to_f # to_f converts to float
    return angle.round
  else
    return round2(n*((nsig^j)+0.5)/(nsig^n))
  end
end

[360,100].each do |n|
  puts "\nFor array length #{n}:\n"
  (1..12).each do |i|
    puts 'Element %d goes to position %d.' % [ i, f(i,n) ]
  end
end

输出:

For array length 360:
Element 1 goes to position 0.
Element 2 goes to position 180.
Element 3 goes to position 90.
Element 4 goes to position 270.
Element 5 goes to position 45.
Element 6 goes to position 135.
Element 7 goes to position 225.
Element 8 goes to position 315.
Element 9 goes to position 23.
Element 10 goes to position 68.
Element 11 goes to position 113.
Element 12 goes to position 158.

For array length 100:
Element 1 goes to position 0.
Element 2 goes to position 50.
Element 3 goes to position 25.
Element 4 goes to position 75.
Element 5 goes to position 13.
Element 6 goes to position 38.
Element 7 goes to position 63.
Element 8 goes to position 88.
Element 9 goes to position 6.
Element 10 goes to position 19.
Element 11 goes to position 31.
Element 12 goes to position 44.

基本思想是可视化圆圈周围项目的位置。如果你查看基于0的索引的位,那么你可以快速查看索引的位长和它们放在圆周的位置之间的模式。

例如,元件5,6,7,8如下放置。首先,减去1使它们基于0,并观察位:

4: 100
5: 101
6: 110
7: 111

这些是长度为3(位大小)的所有索引。它们放置在圆周围的45°,135°,225°,315°位置。然后只是算术和舍入以转换为圆形数组中的索引。

这是JavaScript中的一个版本:http://jsfiddle.net/gfj7Lpya/3/


OP编辑1&amp; 2,在JavaScript中:

// i is 0-based. Return value in [0,1).
function f( i )
{
  if( i === 0 ) return 0;
  var ndigits = Math.floor(Math.log(i)/Math.LN2); // in base 2
  return ((1<<ndigits^i)<<1|1) / (2<<ndigits);
}

JSFiddle:http://jsfiddle.net/gfj7Lpya/4/

例如,要将此值应用于360的数组“长度”,只需将输出乘以:

360 * f(8) // 22.5