#54742: Python解題思路,不是最好,但是能跑


abc1231334 (tl32m)


先讀題。其實這題就是要窮舉組合數。

以範例一來說:
  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="")

以上程式碼參考,一定還有可以優化的點,各位加油!