如何随机约束列表(1和2,3和4,5和6不相邻)?

时间:2017-06-21 05:45:20

标签: python algorithm random

我想要随机分析6个测试题,以及正确的答案。问题#1和#2,#3和#4,#5和#6属于同一类型。为了不让测试变得太容易,我不希望连续显示#1和#2(对于这个问题,不要#3和#4,或#5和#6)。

为此目的,我认为我应该使用这个约束来改变列表[1, 2, 3, 4, 5, 6]:1和2,3和4,5和6是相邻。例如,[ 1,2 ,4,6,3,5]是不可接受的,因为1和2彼此相邻。然后,我想将新订单应用于问题列表和答案列表。

作为编程新手,我只知道如何在没有约束的情况下对列表进行随机播放,如下所示:

question = [1, 3, 5, 2, 4, 6]
answer = ['G', 'Y', 'G', 'R', 'Y', 'R']
order = list(zip(question, answer))
random.shuffle(order)
question, answer = zip(*order)

任何帮助将不胜感激!

5 个答案:

答案 0 :(得分:5)

这是一种“蛮力”的方法。它只是重复洗牌,直到找到有效的排序:

import random

def is_valid(sequence):
    similar_pairs = [(1, 2), (3, 4), (5, 6)]
    return all(
        abs(sequence.index(a) - sequence.index(b)) != 1
        for a, b in similar_pairs
    )

sequence = list(range(1, 7))
while not is_valid(sequence):
    random.shuffle(sequence)

print(sequence)

# One output: [6, 2, 4, 5, 3, 1]

对于这么小的输入,这很好。 (计算机很快。)对于更长的输入,你想要考虑做一些更高效的事情,但听起来你是在采用一种简单的实用方法,而不是理论上最优的方法。

答案 1 :(得分:1)

我看到两种简单的方法:

  1. 如果符合约束条件,则随机播放列表并接受随机播放,否则重复播放。

  2. 迭代地对数字进行采样并使用约束来限制可能的数字。例如,如果您首先绘制1,则第二次绘制可以是3..6。这也可能导致解决方案不可行,因此您必须考虑到这一点。

答案 2 :(得分:1)

使用列表元素作为顶点绘制图形。如果元素u和v在输出列表中可以相邻,则在它们之间绘制边(u,v),否则不要。

现在你必须在这张图上找到汉密尔顿路径。这个问题通常是难以解决的(NP-complete),但如果图形几乎完成(约束很少,即缺少边缘),它可以通过DFS有效地解决。

对于像您的示例中的小型输入集,可能更容易生成所有排列,然后过滤掉那些违反其中一个约束的排列。

答案 3 :(得分:0)

你可以试试这个。这适用于小型列表。正如您在下面看到的,我使用了一组python集来表示约束。代码构建了逐个元素所需的排列。

如果在某些时候,列表中的其余元素都受到约束的限制,那么逐个元素构建元素会导致无效排列。

示例:如果代码生成4,1,3,2,6它被强制尝试使用5作为最后一个元素,但这是无效的,所以函数尝试进行另一个排列。

生成随机混洗并检查其是否有效(smarx给出的答案)比蛮力方法(在性能方面)更好。

注意:如果没有可能满足约束的排列,该函数将导致无限循环。

import random

def shuffler(dataList, constraints):
    my_data_list = list(dataList)
    shuffledList = [random.choice(dataList)]
    my_data_list.remove(shuffledList[0])
    for i in range(1, list_size):
        prev_ele = shuffledList[i - 1]
        prev_constraint = set()
        for sublist in constraints:
            if prev_ele in sublist:
                prev_constraint = set.union(prev_constraint, sublist)
        choices = [choice for choice in my_data_list if choice not in prev_constraint]
        if len(choices) == 0:
            print('Trying once more...')
            return shuffler(dataList,constraints)
        curr_ele = random.choice(choices)
        my_data_list.remove(curr_ele)
        shuffledList.append(curr_ele)
    return shuffledList

if __name__ == '__main__':
    dataList = [1, 2, 3, 4, 5, 6]
    list_size = len(dataList)
    constraints = [{1,2},{3,4},{5,6}]
    print(shuffler(dataList,constraints))

答案 4 :(得分:0)

您可以尝试以下方式:

shuffle the list
while (list is not good)
  find first invalid question
  swap first invalid question with a different random question
endwhile

我还没有完成任何计时,但它可能比重新整理整个列表要快。它在第一个无效问题之前部分保留了有效部分,因此它应该更快地达到良好的排序。