Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 一组学生可以以多少种方式坐成一排,同一班级的学生必须轮流坐_Algorithm_Permutation - Fatal编程技术网

Algorithm 一组学生可以以多少种方式坐成一排,同一班级的学生必须轮流坐

Algorithm 一组学生可以以多少种方式坐成一排,同一班级的学生必须轮流坐,algorithm,permutation,Algorithm,Permutation,有来自N班级的M学生,A[i]是来自i班级的学生人数,sum(A[i])==M。所有这些学生将排成一排,有M个座位,同一班级没有两个学生坐在一起 这些M学生可以通过多少种有效方式坐成一排 比如说,, 如果N=2,A={1,2}, 输出应为2 如果N=2,A={1,3}, 输出应为0 如果N=3,A={1,2,3}, 输出应该是120 技术规格: N

有来自
N
班级的
M
学生,
A[i]
是来自
i
班级的学生人数,
sum(A[i])==M
。所有这些学生将排成一排,有
M
个座位,同一班级没有两个学生坐在一起

这些
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


如果输出大于100000007,则大于输出(结果%100000007)。

此解决方案可能不是最优的,但我认为这是一个良好的开端

此问题有两个组成部分:

  • 将每个座位标记为一个类别(X种方式)
  • 为学生分配座位(Y方式)
  • 最终答案等于X*Y

    第二部分很简单。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)+

    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
    
    然而,使用
    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
    

    有人想改进吗?

    首先请注意,给定输入列表
    a
    的有效座位安排,
    sum(a)=n
    ,当新的
    m
    等级到达时,计算有效座位安排的数量很容易:

    • m
      新生安排在所有可能的
      n+1
      有效位置(有
      n
      老学生,这意味着
      n+1
      有效位置)。这是组合的精确定义,有
      C(n+1,m)
      这样的组合
    • 然后排列
      m
      新生,以获得所有可能的有效座位安排
    因此,新的
    m
    等级的到来将有效座位安排的数量乘以
    C(n+1,m)*m。这建议使用以下算法(在Python中):

    导入数学
    导入scipy.misc
    定义f(A):
    如果len(A)==2:
    a、 b=a
    如果a==b:
    #不考虑顺序的两个解o+o+和+o+o,然后乘以2!*2.在类中获取所有可能的命令
    返回数学阶乘(a)*数学阶乘(b)*2
    elif abs(a-b)=1:
    #o+o+o不考虑顺序,然后乘以2!*3.在类中获取所有可能的命令
    返回数学阶乘(a)*数学阶乘(b)
    否则:#没有解决方案
    返回0
    否则:#有效排列数乘以C(n+1,m)*m!
    返回和(f(A[:i]+A[i+1:])*scipy.misc.comb(和(A)-ai+1,ai)*枚举(A)中i,ai的数学阶乘(ai))
    
    让我们检查一下,我们得到的结果是否与OP的示例相同:

    f([1,2])
    2.
    f([1,3])
    0
    f([1,2,3])
    120
    
    它起作用了!让我们试着让30名学生参加三个班:

    f([30,30,30])
    2.605879410003256e+115#这比宇宙中重子的数量还要多!
    
    “同一个班级没有两个学生坐在一起。”只表示“必须交替”表示
    N==2
    如果你不知道什么是排列,可能会帮助你找到你想要的。我不确定这是否属于stackoverflow,而且看起来很像家庭作业,但对一个有趣的问题进行一次向上投票。若其中一个A[i]大于M/2+1,那个么答案是0。。。很难得到正确的公式。正如@Vesper所暗示的,这是一个比看起来复杂得多的问题,因为有些情况下没有解决方案(M=12,N=2,a={10,2}),有些情况下有很多解决方案,甚至可能有唯一解决方案。不可能有一个简单的封闭式公式或算法。
    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