根据喜好将 n 个人安排在 x 2 床房和 y 3 床房

问题描述 投票:0回答:1

我在解决以下班级旅行问题时遇到了麻烦:

有54名学生,必须被分成14间3床房和6间2床房。每个人都有一个或多个最喜欢的人,他/她想与他们共享一个房间。

首选项= {'studen1':[studnet2,student3],'student2':[student3,student 1],...}

我能够计算出每种可能的三重匹配(在 3 个学生组成的小组中,每个人都互相喜欢)和正常匹配(在 2 个学生组成的小组中,每个人都互相喜欢)

我考虑过尝试计算学生的每种可能的组合(或至少是偏好),并尝试通过根据房间的好坏程度提供分数来获得最佳结果: 好的3人间:6分 好2房:4分 平均3人间:5分 平均三床房:4分 中差3房:3分 差3er房间:2分 非常差的三床房:1分 中2房:1分

现在我有点不知所措,不知道如何在不需要使用超级计算机的情况下解决问题;)

我对我的代码非常糟糕感到抱歉;) 这是我计算正常匹配和三重匹配后的代码:

students_with_room = []
real_rooms = []

exit_loop = False

real_rooms = {'2A': [], '2B': [], '2C': [], '2D': [], '2E': [], '2F': [],'3A': [], '3B': [], '3C': [], '3D': [], '3E': [], '3F': [], '3G': [], '3H':    [], '3I': [], '3J': [], '3K': [], '3L': [], '3M': [], '3N': [],}    
for student in students:
    if student not in students_with_room: 
        if triple_matches[student] == None:
            for room in real_rooms:
                if real_rooms[room] == [] and '2' in room:
                    if len(matches[student]) != 0:
                        for i in range(len(matches[student])):
                                if len(set([matches[student][i], student]).intersection(students_with_room)) == 0:
                                    real_rooms[room] = [matches[student][i], student]                        
                                    students_with_room = students_with_room + [matches[student][i]]
                                    students_with_room = students_with_room + [student]
                                    exit_loop = True
                                    break   
                                else: 
                                    pass


                    else: 
                        pass  
                if exit_loop == True:
                    break   
                if real_rooms[room] == [] and '3' in room:
                    pass    
            exit_loop = False   
        else:
            for room in real_rooms: 
                if student not in students_with_room:   
                    if real_rooms[room] == [] and '3' in room:
                        real_rooms[room] = [triple_matches[student][0], triple_matches[student][1], student]                        
                        students_with_room = students_with_room + triple_matches[student]
                        students_with_room = students_with_room + [student]
    else: 
        pass

for triple_match in triple_matches:
    already_done = False
    if triple_matches[student] == None:
        pass
   
    else:            
        if student in students_with_room:
            already_done = True 
        if not already_done:
            students_with_room.append(triple_matches[student][0])
            real_rooms
python combinatorics assign
1个回答
0
投票

好吧,这个问题看起来有点有趣,这是一个使用 networkx 的简单但

强力
解决方案的示例。请注意,一旦学生数量增加,运行速度就会变慢。我仍然建议将其视为多个背包问题,但希望这足以让您以不同的方式思考该问题。

import networkx as nx
import itertools
from collections import defaultdict 

students_to_room = 3
preferences = {"A":["B", "C", "F"], 
               "B":["A", "D"],
               "C":["A", "D"], 
               "D":["C", "B"], 
               "E":["F", "G"],
               "F":["G", "A"],
               "G":["F", "D"],
              }

G = nx.complete_graph(preferences.keys())

N_HOTEL_ROOMS = 3

student_ids = list(preferences.keys())
for key in student_ids:
    for k in student_ids:
        if k in preferences[key]:
            # arbitrary value, if two students like eachother
            G[key][k]['weight'] = 2
        else:
            # I am lazy
            try:
                # aribtrary value, if two students don'w seem to like eachother
                G[key][k]['weight'] = -1
            except:
                pass
def path_weight(G, path):
    # Function to calculate the weight of a path
    weight = 0
    for i in range(len(path) - 1):
        weight += G[path[i]][path[i + 1]]['weight']
        if len(path) > 1:
            weight += G[path[0]][path[-1]]['weight']
    return weight 

def max_path(G, n1, n2, cutoff = students_to_room -1):
    # Find the path on G between nodes n1 and n2 of length
    # cutoff with the largest edge weight
    all_paths = nx.all_simple_paths(G, n1, n2, cutoff= cutoff)
    #all_paths = [path for path in all_paths if len(path) == cutoff + 1]
    
    path = max(all_paths, key=lambda path: path_weight(G, path))
    
    return path, path_weight(G, path)


def is_allowed(combination, student_ids = student_ids):
    # Function to see if we have any students in multile rooms 
    #-- if so we can throw away the combination, and we also 
    # want to make sure all students are accounted for 
    all_elements = sum(combination, ())
    counter = defaultdict(int)
    for c in all_elements:
        counter[c] += 1
    return max(counter.values()) <= 1 and set(all_elements) == set(student_ids)

combos = []
# Find unique pairs of two students, so we can find
# which other students will go with them 
room_assignments = [2,3]
for assignment in room_assignments:
    for comb in itertools.combinations(keys, assignment):
        combos.append(comb)
    
paths = {}
# Now for each unique pair of students, find a path of length
# sutends_to_room between them and find the weight of the path
# i.e. the "score" of putting those students to a room

for path in combos:
    weight = path_weight(G,path)
    paths[tuple(path)] = weight

# Get all possible combinations of students between three hotel rooms
allowable = itertools.combinations(paths.keys(), N_HOTEL_ROOMS)
# Only accept solutions where a student isn't between each room, 
# and when we have all students
allowable = [a for a in allowable if is_allowed(a)]

max_paths = {}
for path in allowable:
    max_paths[path] = sum([paths[a] for a in path])
# # sort the result, and the first entry is our "best" solution
s =  dict(sorted(max_paths.items(), key=lambda item: item[1], reverse=True))
room_assignment = list(s.keys())[0]

print("Room assignment", room_assignment, "Happiness score", s[room_assignment])

>>> Room assignment (('A', 'B'), ('C', 'D'), ('E', 'F', 'G')) Happiness score 7

这里,

s
是我们最终允许的组合,权重最大的关键将是我们的最佳解决方案——即最快乐学生的房间分配。

编辑:抱歉,我读错了原来的问题,我没有意识到你已经在房间之间设置了学生编号分配,这应该可以解决这个问题。

© www.soinside.com 2019 - 2024. All rights reserved.