我在处理SPOJ 问题 423:作业时遇到问题。
该问题要求我计算 n 个独特主题的可能分配给 n 个独特学生的数量,以便每个学生都能获得他/她喜欢的一个主题。我想出了一种将输入解析为名为preferences
. 每个内部列表都是一个学生喜欢的主题列表(用 0 到 n-1 之间的整数表示)。
例如对于输入:
1 1 1
1 1 1
1 1 1
我明白了[[0, 1, 2], [0, 1, 2], [0, 1, 2]]
。
对于输入:
1 0 0 1 0 0 0 0 0 1 1
1 1 1 1 1 0 1 0 1 0 0
1 0 0 1 0 0 1 1 0 1 0
1 0 1 1 1 0 1 1 0 1 1
0 1 1 1 0 1 0 0 1 1 1
1 1 1 0 0 1 0 0 0 0 0
0 0 0 0 1 0 1 0 0 0 1
1 0 1 1 0 0 0 0 0 0 1
0 0 1 0 1 1 0 0 0 1 1
1 1 1 0 0 0 1 0 1 0 1
1 0 0 0 1 1 1 1 0 0 0
我得到清单[[0, 3, 9, 10], [0, 1, 2, 3, 4, 6, 8], [0, 3, 6, 7, 9], [0, 2, 3, 4, 6, 7, 9, 10], [1, 2, 3, 5, 8, 9, 10], [0, 1, 2, 5], [4, 6, 10], [0, 2, 3, 10], [2, 4, 5, 9, 10], [0, 1, 2, 6, 8, 10], [0, 4, 5, 6, 7]]
。
现在我需要做的是计算我可以从每个内部列表中选择一个唯一数字的方式的数量,以便没有元素被选择两次,并且在所有选择中,0 到 n-1 之间的每个数字都被选择一次。对于第一个示例输入,这是微不足道的,它是3! = 6
. 但是在第二个例子中,我很难找到一种方法来计算有效选择的数量。对于第二个输入,他们给出的答案是 7588,但我不知道如何获得该答案。
我已经尝试过查找 [0,...,n-1] 的所有排列并尝试查看它们是否是基于集合成员资格的有效组合的蛮力方法,但它太慢了,当我真的崩溃时我的电脑试图遍历11! = 39916800
排列。所以我需要做的是找到一种更有效的计算方法。
到目前为止,这是我的代码。它目前所做的只是将来自标准输入的输入解析为一个名为首选项的列表列表并将其打印到标准输出。
def main():
t = int(raw_input())
from itertools import repeat
for _ in repeat(None, t):
n = int(raw_input())
preferences = [[] for _ in repeat(None, n)]
for student in xrange(n):
row = map(int, raw_input().split())
for i in xrange(len(row)):
if row[i] == 1:
preferences[student].append(i)
print preferences
if __name__ == '__main__':
main()
有什么方法可以用来有效地计算这个吗?欢迎任何提示/提示。我不指望任何人为我解决问题。我只是对如何处理这个问题感到困惑。