问题
Problem statement
I would like to achieve the following: (could be used for example to organize some sort of a speeddating event for students)
Create a schedule so people talk to each other one-on-one and this to each member of the group. but with restrictions.
- Input: list of people. (eg. 30 people)
- Restrictions: some of the people should not talk to each other (eg. they know each other)
- Output: List of pairs (separated into sessions) just one solution is ok, no need to know all of the possible outcomes
Example
eg. Group of 4 people
- John
- Steve
- Mark
- Melissa
Restrictions: John - Mellisa -> NO
Outcome
Session one
- John - Steve
- Mark - Melissa
Session two
- John - Mark
- Steve - Melissa
Session three
- Steve - Mark
John and Mellisa will not join session three as it is restriction.
Question
Is there a way to approach this using Python or even excel?
I am especially looking for some pointers how this problem is called as I assume this is some Should I look towards some solver? Dynamic programming etc?
回答1:
This is a fairly naive implementation:
from itertools import combinations
from typing import Set, List, Generator
def generate_sessions(people: Set, excl: List[Set]) -> Generator[List[Set], None, None]:
# all the pairings you need are all possible pairings, except the exclusions
needed_pairings = [set(pair) for pair in combinations(people, 2)]
for pair in excl:
needed_pairings.remove(pair)
# while there pairing that haven't happened yet
while needed_pairings:
# each session starts empty
session = []
# keep track of all people still available for this session
available = set(people)
# create an iterator, so we can loop over the needed pairings
iter_needed_pairings = iter(needed_pairings)
# as long as there are more than 2 people still waiting and there's a pair left in the needed pairings
while (len(available) > 1) and (pair := next(iter_needed_pairings, False)):
# are both people in the pair in the group of available people?
if available.intersection(pair) == pair:
# then they can meet in this session
session.append(pair)
# and they're no longer available
available -= pair
# once we have a session, remove the pairs in it from the pairings still needed
for pair in session:
needed_pairings.remove(pair)
# yield the session
yield session
print(list(generate_sessions(people={'John', 'Steve', 'Mark', 'Melissa'}, excl=[{'John', 'Melissa'}])))
Result (can vary, due to unordered nature of sets):
[[{'John', 'Mark'}, {'Melissa', 'Steve'}], [{'John', 'Steve'}, {'Melissa', 'Mark'}], [{'Mark', 'Steve'}]]
This generates sessions until everyone has met. You could just get the next()
from the generator until you have enough sessions. The only downside to this approach is that it may find a sessions where a few people are waiting before a session that has more people meeting. You could solve that by sorting the sessions by length, but of course that means generating all of them.
Edit: I added typing info, to make it clear what the expected types are, but of course it doesn't need that to work.
回答2:
Your given information is pretty generous, you have a set of all the students, and a set of no-go pairs (because you said it yourself, and it makes it easy to explain, just say this is a set of pairs of students who know each other). So we can iterate through our students list creating random pairings so long as they do not exist in our no-go set, then expand our no-go set with them, and recurse on the remaining students until we can not create any pairs that do not exist already in the no-go set (we have pairings so that every student has met all students).
来源:https://stackoverflow.com/questions/65163061/create-a-schedule-where-a-group-of-people-all-talk-to-each-other-with-restrict