[英]Get n * k unique sets of 2 from list of length n in Python
我有以下 Python 脑筋急转弯:我们安排了一个有 48 名参与者的 30 天计划。 在该计划的每一天,参与者都是二人一组。 参与者不能有两次相同的伙伴,并且所有参与者必须每天建立伙伴关系。 PS我希望我的数学在标题中是正确的。
我已经管理了一个实现,但感觉很笨重。 有没有一种有效的方法来做到这一点? 也许以某种方式使用笛卡尔积? 非常感谢所有反馈和提示。
# list of people: 48
# list of days: 30
# each day, the people need to be split into pairs of two.
# the same pair cannot occur twice
import random
from collections import Counter
class person ():
def __init__ (self, id):
self.id = id
class schedule ():
def __init__ (self, days):
self.people_list = []
self.days = days
self.placed_people = []
self.sets = []
def create_people_list(self, rangex):
for id in range(rangex):
new_person = person(id)
self.people_list.append(new_person)
print(f"{len(self.people_list)} people and {self.days} days will be considered.")
def assign_pairs(self):
for day in range(self.days): # for each of the 30 days..
print("-" * 80)
print(f"DAY {day + 1}")
self.placed_people = [] # we set a new list to contain ids of placed people
while Counter([pers.id for pers in self.people_list]) != Counter(self.placed_people):
pool = list( set([pers.id for pers in self.people_list]) - set(self.placed_people))
# print(pool)
person_id = random.choice(pool) # pick random person
person2_id = random.choice(pool) # pick random person
if person_id == person2_id: continue
if not set([person_id, person2_id]) in self.sets or len(pool) == 2:
if len(pool) == 2: person_id, person2_id = pool[0], pool[1]
self.sets.append(set([person_id, person2_id]) )
self.placed_people.append(person_id)
self.placed_people.append(person2_id)
print(f"{person_id} {person2_id}, ", end="")
schdl = schedule(30) # initiate schedule with 30 days
schdl.create_people_list(48)
schdl.assign_pairs()
输出:
48 people and 30 days will be considered.
--------------------------------------------------------------------------------
DAY 1
37 40, 34 4, 1 46, 13 39, 12 35, 18 33, 25 24, 23 31, 17 42, 32 19, 36 0, 11 9, 7 45, 10 21, 44 43, 29 41, 38 16, 15 22, 2 20, 26 47, 30 28, 3 8, 6 27, 5 14,
--------------------------------------------------------------------------------
DAY 2
42 28, 25 15, 6 17, 2 14, 7 40, 11 4, 22 37, 33 20, 0 16, 3 39, 19 47, 46 24, 12 27, 26 1, 34 10, 45 8, 23 13, 32 41, 9 29, 44 31, 30 5, 38 18, 43 21, 35 36,
--------------------------------------------------------------------------------
DAY 3
8 28, 33 12, 40 26, 5 35, 13 31, 29 43, 44 21, 11 30, 1 7, 34 2, 47 45, 46 17, 4 23, 32 15, 14 22, 36 42, 16 41, 37 19, 38 3, 20 6, 10 0, 24 9, 27 25, 18 39,
--------------------------------------------------------------------------------
[...]
--------------------------------------------------------------------------------
DAY 29
4 18, 38 28, 24 22, 23 33, 9 41, 40 20, 26 39, 2 42, 15 10, 12 21, 11 45, 46 7, 35 27, 29 36, 3 31, 19 6, 47 32, 25 43, 13 44, 1 37, 14 0, 16 17, 30 34, 8 5,
--------------------------------------------------------------------------------
DAY 30
17 31, 25 7, 6 10, 35 9, 41 4, 16 40, 47 43, 39 36, 19 44, 23 11, 13 29, 21 46, 32 34, 12 5, 26 14, 15 0, 28 24, 2 37, 8 22, 27 38, 45 18, 3 20, 1 33, 42 30,
谢谢你的时间! 另外,一个后续问题:我如何计算是否可以解决任务,即每天将所有参与者安排成独特的对?
循环赛非常容易组织。 事实上,算法非常简单,你可以在没有任何纸张或计算机的情况下组织人类之间的循环赛,只需给人类简单的指令即可。
你有一个偶数N = 48
个人要配对。 假设您有一张长桌,一侧有N // 2
个座位,另一侧面向N // 2
个座位。 请所有人坐在那张桌子旁。
这是您的第一次配对。
将其中一个座位称为“1 号座位”。
移动到下一个配对:1 号座位的人不动。 每隔一个人顺时针绕桌子移动一个座位。
Current pairing
1 2 3 4
8 7 6 5
Next pairing
1 8 2 3
7 6 5 4
# a table is a simple list of humans
def next_table(table):
return [table[0]] + [table[-1]] + table[1:-1]
# [0 1 2 3 4 5 6 7] -> [0 7 1 2 3 4 5 6]
# a pairing is a list of pairs of humans
def pairing_from_table(table):
return list(zip(table[:len(table)//2], table[-1:len(table)//2-1:-1]))
# [0 1 2 3 4 5 6 7] -> [(0,7), (1,6), (2,5), (3,4)]
# a human is an int
def get_programme(programme_length, number_participants):
table = list(range(number_participants))
pairing_list = []
for day in range(programme_length):
pairing_list.append(pairing_from_table(table))
table = next_table(table)
return pairing_list
print(get_programme(3, 8))
# [[(0, 7), (1, 6), (2, 5), (3, 4)],
# [(0, 6), (7, 5), (1, 4), (2, 3)],
# [(0, 5), (6, 4), (7, 3), (1, 2)]]
print(get_programme(30, 48))
如果你想在人类是自定义对象,而不是整数,可以更换第二个参数number_participants
通过名单table
直接; 然后用户可以提供他们想要的任何列表:
def get_programme(programme_length, table):
pairing_list = []
for day in range(programme_length):
pairing_list.append(pairing_from_table(table))
table = next_table(table)
return pairing_list
print(get_programme(3, ['Alice', 'Boubakar', 'Chen', 'Damian']))
# [[('Alice', 'Damian'), ('Boubakar', 'Chen')],
# [('Alice', 'Chen'), ('Damian', 'Boubakar')],
# [('Alice', 'Boubakar'), ('Chen', 'Damian')]]
如果有N
个人类,每个人类可以与N-1
不同的人类配对。 如果N
是偶数,那么循环循环方法将确保前N-1
轮是正确的。 之后,算法是周期性的:第N
轮将与第一轮相同。
因此,当且仅当programme_length < number_participants
且参与者数量为偶数时,才存在解决方案; 在这种情况下,循环算法将找到解决方案。
如果参加人数是奇数,那么节目的每一天,必须至少有一个人没有配对。 在这种情况下仍然可以应用循环赛:添加一个额外的“虚拟”人类(通常称为bye-player )。 就算法而言,虚拟人的行为与正常人完全一样。 每一轮,一个不同的真人将与假人配对,这意味着他们本轮没有与真人配对。 使用此方法,您只需要programme_length <= number_participants
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.