来自M
个班级的N
名学生,A[i]
是来自class_i
,sum(A[i]) == M
的学生人数。所有这些学生将坐在M
个座位上,并且没有2个同一班级的学生坐在一起。
这些M
学生可以连续坐多少个有效的方法?
例如, 如果N = 2,A = {1,2}, 输出应为2;
如果N = 2,A = {1,3}, 输出应为0;
如果N = 3,A = {1,2,3}, 输出应为120。
技术规格: N< 47; A [i]< 47; 总和(A)< 447;
如果输出大于1000000007,则输出(结果%1000000007)。
答案 0 :(得分:0)
此解决方案可能不是最佳解决方案,但我认为这是一个良好的开端。
此问题有两个组成部分:
最终答案等于X * Y.
第2部分非常简单。 Y = A(1)! A(2)! ...... * A(N)!
计算第一部分虽然很棘手。您可以使用DP来解决它。复杂性= N * A(1) A(2) ... * A(N)(这对我来说太贵了)
DP问题是:
F(a1,a2,..,an,last_letter = 1)= F(a1-1,a2,..,an,last_letter!= 1)+ F(a1,a2-1,..,an ,last_letter!= 1)+ ... + F(A1,A2,...,AN-1,last_letter!= 1)
答案 1 :(得分:0)
考虑以下python代码:
import math
mem={}
def get_id(A, forbidden):
count = {}
for a in A:
if a<>forbidden:
n = A[a]
count[n] = count.get(n,0)+1
return frozenset( [A.get(forbidden, 0)] + count.items() )
def class_seatings(A, forbidden=None):
if sum(A.values())==1:
if forbidden in A:
return 0
else:
return 1
ssum = 0
for a in A:
if a <> forbidden:
n = A[a]
A2 = dict(A)
if n==1:
del A2[a]
else:
A2[a] -= 1
id = get_id(A2, a)
if id not in mem:
mem[id] = class_seatings(A2, a)
cs = mem[id]
ssum += cs
return ssum
def student_seatings(A):
assert all(map(lambda x: x>0, A.values()))
facts = map(lambda x: math.factorial(x), A.values())
mult = reduce(lambda x,y: x*y, facts, 1)
return mult*class_seatings(A) % 1000000007
看起来基本情况正确:
>>> student_seatings( {1:1, 2:2} )
2
>>> student_seatings( {1:1, 2:2, 3:3} )
120
>>> student_seatings( {1:1, 2:3} )
0
>>> student_seatings( {1:2, 2:2} )
8
然而,在你提到的要求之前,使用mem
和get_id
的基本记忆方案开始崩溃。要看到这一点,请观看进展
mem={}
for upper in range(2,11):
A = dict( (x,x) for x in range(1,upper) )
print len(A), student_seatings(A)
print len(mem)
产生
1 1
0
2 2
4
3 120
20
4 309312
83
5 579005048
329
6 462179000
1286
7 481882817
5004
8 678263090
19447
9 992777307
75581
有人关心改善吗?
答案 2 :(得分:0)
首先请注意,如果输入列表A
的有效座位安排为sum(A)=n
,则当新的m
类到达时,可以轻松计算有效座位安排的数量:
m
名新学生适应所有可能n+1
个有效职位(n
名有学生,n+1
有效职位。这是组合的确切定义,并且有C(n+1,m)
个这样的组合。 m
名新生置换,以获得所有可能的有效座位安排。 因此,新类型m
的到来使有效座位安排的数量乘以C(n+1,m) * m!
。这表明以下算法(在Python中):
import math
import scipy.misc
def f(A) :
if len(A) == 2 :
a,b = A
if a == b :
# two solutions o+o+ and +o+o without order consideration, then multiply by 2! * 2! to get all possible orders within classes
return math.factorial(a) * math.factorial(b) * 2
elif abs( a - b ) == 1 :
# o+o+o without order consideration, then multiply by 2! * 3! to get all possible orders within classes
return math.factorial(a) * math.factorial(b)
else : # no solution
return 0
else : # the number of valid arrangement is multiplied by C(n+1,m) * m!
return sum( f(A[:i]+A[i+1:]) * scipy.misc.comb( sum(A)-ai + 1, ai ) * math.factorial(ai) for i, ai in enumerate(A) )
让我们检查一下我们得到的结果与OP的例子相同:
f( [ 1,2 ] )
2
f( [ 1,3 ] )
0
f( [ 1, 2, 3 ] )
120.0
有效!让我们试试30个学生的三个班级:
f( [ 30, 30, 30 ] )
2.6058794190003256e+115 # this is greater than the number of baryons in the universe!