先讀題。其實這題就是要窮舉組合數。
以範例一來說:
5種專長項目
2個班
每班4人
所有學生之中,要挑3人出賽
所有組合,按照升序排列,輸出第2組
8個學生的專長項目分別代號為3 1 2 4 1 3 1 5
要窮舉組合數,可以想到DFS
以下這段程式碼,可以列出所有的組隊可能 (沒有專長、每班只能派兩人的限制的話)
n, m, r, k, t = 5, 2, 4, 3, 2
visited = [False] * m * r # 紀錄該學生是否被用過了
combination = [0] * k # 紀錄答案
def dfs(layer:int, start:int):
# 訪問到最底層就return
if layer == k:
print(combination)
return
for s in range(start, m*r):
# 把訪問的內容記錄到combinaiton
combination[layer] = s + 1
# 訪問下一層,再出來
visited[s] = True
dfs(layer+1, s+1)
visited[s] = False
dfs(0,0)
以這個框架,再加入條件
1. 每種技能只能有一個
2. 每班只能有兩人
所以需要創設資料格式,用來記錄每種技能是不是用過了,以及每班使用多少人了。
並且在訪問該學生時,檢查這兩個條件,如果都符合了,才在combination記錄下來,
from sys import stdin
# n種專長項目
# m個班級
# 每班r個人
# 出去比賽,一隊要有k人
# t:求所有組合按照升序的第t項目
n,m,r,k,t = map(int, input().split())
p = input()
student_specialities = list(map(int, p.split()))
student_num = list(map(str,range(1,m*r+1)))
student_class = []
for i in range(1,m+1):
student_class += ([i] * r)
# 紀錄dfs訪問狀態
class_student_count = [0] * m # 每個班級有派出多少人了
speciality_is_used = [False] * n # 該專長是否有被使用過
combination = [""] * k # 紀錄當前訪問狀態
ans_count = 0
# 找到題目瞬間用來退出循環
class FoundAns(Exception):
pass
def dfs(layer:int, start:int):
global ans_count
if layer == k:
ans_count += 1
if ans_count == t:
raise FoundAns()
return
for i in range(start, m*r):
if ans_count == t:
return
_spe_index = int(student_specialities[i]) - 1
_class_index = student_class[i] - 1
if (not speciality_is_used[_spe_index]) and (class_student_count[_class_index] < 2):
combination[layer] = i + 1
class_student_count[_class_index] += 1
speciality_is_used[_spe_index] = True
dfs(layer+1, i+1) # 訪問下一層
speciality_is_used[_spe_index] = False
class_student_count[_class_index] -= 1
else:
continue
try:
dfs(0, 0)
except FoundAns:
print(*combination, sep=" ",end="")
以上程式碼參考,一定還有可以優化的點,各位加油!