【问题标题】:Generating random "break points" in a sequence a minimum distance from each other在序列中生成随机“断点”,彼此之间的距离最小
【发布时间】:2013-10-08 04:41:52
【问题描述】:

我有一个包含n 元素的序列,我想随机k“断点”每个至少minDist 彼此远离(和末端)。例如,对于n=9, k=2, minDist=2,我想以相等的概率生成以下之一:

[2 4][2 5][2 6][2 7][3 5][3 6][3 7][4 6][4 7][5 7]

到目前为止,我想出了:随机放置一个,“禁用”它周围所需数量的节点,然后选择另一个随机数,但这让我觉得效率有点低。我正在用 MATLAB 编程,但任何语言都可以。

我将使用它来初始化一些遗传算法的种群,因此我希望每种可能性都具有相同的可能性,以确保我覆盖了整个搜索空间。仅仅确定性地分布断点是不够的。

【问题讨论】:

  • 您的示例中的[3,7] 是什么?
  • [3,7] 是所需的断点位置吗?如果是这样,如何指定该交互也需要minDist
  • 你举了一个非常令人困惑的例子,伙计。
  • @LuisMendo 这个例子令人困惑,[3 7] 是我想要生成的结果之一。我已经澄清了这个例子,希望现在它更容易理解了。
  • @VPeric 在您的示例中,如果 minDist==2 并且您的元素编号为 1 到 9,那么您的断点中不应该有 2,最小的不应该是 3。

标签: algorithm matlab


【解决方案1】:

这里有个函数可以生成所有可能的断点组合,你可以把它们存储在一个列表中而不是打印出来,然后统一选择其中一个:

static void breakpointCombinations(List<int> possiblePositions, List<int> breakpointCombination, int remainingBreakpoints, int minSpace, int currentPos)
{
    if (remainingBreakpoints == 0)
    {
        foreach (int tempPos in breakpointCombination)
        {
            Console.Write(tempPos + " ");
        }
        Console.WriteLine();
    }

    else if (remainingBreakpoints * minSpace > possiblePositions.Count - currentPos)
        return;

    else
    {
        if (currentPos >= minSpace - 1)
        {
            breakpointCombination.Add(possiblePositions[currentPos]);
            breakpointCombinations(possiblePositions, breakpointCombination, remainingBreakpoints - 1, minSpace, currentPos + minSpace);
            breakpointCombination.Remove(possiblePositions[currentPos]);
        }

        breakpointCombinations(possiblePositions, breakpointCombination, remainingBreakpoints, minSpace, currentPos + 1);
    }
}

函数调用(在本例中,10 个元素,2 个断点,最小空间为 2):

static void Main(string[] args)
{
    List<int> Positions = new List<int>();
    for (int i = 0; i < 10; i++)
    {
        Positions.Add(i);
    }

    breakpointCombinations(Positions, new List<int>(), 2, 2, 0);
}

从您的示例中暗示,空格 2 意味着 2 个断点之间应该至少有一个位置(例如,这意味着 [2, 4] 是合法的),我从头到尾处理了空格同一个(这在示例中不一致),这意味着如果元素是 [0, ... ,9],则第一个合法断点位于元素 1 处,最后一个位于元素 8 处。

【讨论】:

  • 它不完全是 matlab,但底层算法也是我的第一个想法。特别是如果您要选择的对数(远)大于可能的对数,这应该是有效的。
  • 我从 1 到 9 对元素进行编号,断点在给定位置“之后”。我的例子有什么不一致的地方?第一个合法位置是 2(所以元素 1 和 2 在断点之前),最后一个合法位置是 7(所以元素 8 和 9 在断点之后)。
  • @VPeric 我不明白你的定义是第一个断点不包括第一个元素(就此而言,可能在那个元素之前......)。无论如何它的语义,算法应该做的工作(改变else if比较&gt;=)。
【解决方案2】:

如果您不介意随机(但很小)的计算时间,您可以使用拒绝方法

  1. 随机生成分布均匀的暂定断点;
  2. 检查它们是否满足您的限制;
  3. 如果没有,请重复。

这确保了每个有效的断点组合的概率相等,而不必一开始就生成所有这些组合。

在 Matlab 中:

done = 0;
while ~done
  breakPoints = sort(randi(n,1,k));
  done = all(diff([0 breakPoints n]) >= minDist);
end

【讨论】:

    【解决方案3】:

    根据您的规范,您可以从左侧开始,并在每个 minDist 元素之后放置断点 k-1 次。

    如果您希望您的部门更加统一分布,您必须修改您的规范。

    【讨论】:

    • 谢谢,我同意我最初的问题令人困惑。无论如何,我希望所有可能性都具有相同的可能性,因此仅像这样分布断点是不够的。
    【解决方案4】:

    其实,如果你想覆盖整个搜索空间,你不应该随机选择点。

    相反,您应该选择所有点,也许以随机顺序。

    这里有一个简单的方法来选择k = 2的所有点:

    n=9;
    minDist = 2;
    p = [];
    for x = minDist:n-minDist*2
       for y = x+minDist:n-minDist
         p = [p;x y]
       end
    end
    

    对于较低的 k 值,您可以简单地添加嵌套循环。

    一旦你有了所有的点,随机挑选它们应该是微不足道的。

    【讨论】:

    • 我宁愿避免写嵌套循环;并不是说任何解决方案都不会退化为此,而只是出于可移植性的目的。
    • @VPeric 如果您基本上想要我提供的功能,但允许任意 k,那么请尝试研究递归。一般来说,这是嵌套 for 循环的自动化方式。
    猜你喜欢
    • 1970-01-01
    • 2013-01-24
    • 1970-01-01
    • 2018-04-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-02
    相关资源
    最近更新 更多