如何应对Vertical Sticks挑战?

时间:2012-04-06 07:41:23

标签: algorithm data-structures probability

此问题取自interviewstreet.com

  

给定整数数组Y = y1,...,yn,我们有n个线段,这样   段i的端点是(i,0)和(i,yi)。想象一下,来自   每个片段的顶部向左侧拍摄水平光线,并拍摄此光线   当它接触另一个段或它碰到y轴时停止。我们   构造一个n个整数的数组,v1,...,vn,其中vi等于   从段顶部射出的射线长度i。我们定义V(y1,...,yn)   = v1 + ... + vn。

     

例如,如果我们有Y = [3,2,5,3,3,4,1,2],那么v1,...,v8 =   [1,1,3,1,1,3,1,2],如下图所示:

     

enter image description here

     

对于[1,...,n]的每个排列p,我们可以计算V(yp1,...,   YPN)。如果我们选择[1,...,n]的均匀随机置换p,那么   是V(yp1,...,ypn)的期望值?

     

输入格式

     

第一行输入包含单个整数T(1 <= T <= 100)。 Ť   测试用例如下。

     

每个测试用例的第一行是单个整数N(1 <= N <= 50)。   下一行包含由a分隔的正整数y1,...,yN   单个空格(0      

输出格式

     

对于每个测试用例输出预期值V(yp1,...,ypn),舍入   小数点后的两位数。

     

示例输入

6
3
1 2 3
3
3 3 3
3
2 2 3
4
10 2 4 4
5
10 10 10 5 10
6
1 2 3 4 5 6
     

示例输出

4.33
3.00
4.00
6.00
5.80
11.15
     

解释

     

案例1:我们有V(1,2,3)= 1 + 2 + 3 = 6,V(1,3,2)= 1 + 2 + 1 = 4,V(2,1,3) =   1 + 1 + 3 = 5,V(2,3,1)= 1 + 2 + 1 = 4,V(3,1,2)= 1 + 1 + 2 = 4,V(3,2,1) =   1 + 1 + 1 = 3.这些值的平均值为4.33。

     

案例2:无论排列是什么,V(yp1,yp2,yp3)= 1 + 1 + 1 =   3,答案是3.00。

     

情况3:V(y1,y2,y3)= V(y2,y1,y3)= 5,V(y1,y3,y2)= V(y2,y3,y1)=   4,V(y3,y1,y2)= V(y3,y2,y1)= 3,这些值的平均值为   4.00。

对于N = 50,问题的天真解决方案将永远运行。我相信可以通过独立计算每根棒的值来解决问题。我仍然需要知道是否有任何其他有效的方法来解决这个问题。我们在什么基础上独立计算每根棒的价值?

3 个答案:

答案 0 :(得分:7)

我们可以通过弄清楚来解决这个问题:

  

如果 k th stick放在 i 位置,该棒的预期射线长度是多少。

然后可以通过将所有位置的所有棒的所有预期长度相加来解决问题。

expected[k][i]成为放在 i 位置的 k 棒的预期光线长度,让num[k][i][length]为排列数 k th stick放入 i 位置,光线长度等于length,然后

  

expected[k][i] = sum( num[k][i][length] * length ) / N!

如何计算num[k][i][length]?例如,对于length=3,请考虑以下图表:

  

... ... GxxxI

I是位置,3'x'表示我们需要3支严格低于I的支杆,而G意味着我们需要一支至少同样高的支杆为I。 让s_i为小于k小棍子的小棍数,g_i是大于或等于k小棍的小棍数,然后我们可以选择g_i中的任何一个放入G位置,我们可以选择任意length s_i来填充x位置,所以我们有:

  

num[k][i][length] = P(s_i, length) * g_i * P(n-length-1-1)

如果I之前的所有位置都小于I,我们在G中不需要更大的支持,即xxxI....,我们有:

  

num[k][i][length] = P(s_i, length) * P(n-length-1)

这是一段可以解决这个问题的Python代码:

def solve(n, ys):
    ret = 0
    for y_i in ys:
        s_i = len(filter(lambda x: x < y_i, ys))
        g_i = len(filter(lambda x: x >= y_i, ys)) - 1

        for i in range(n):
            for length in range(1, i+1):
                if length == i:
                    t_ret = combination[s_i][length] * factorial[length] * factorial[ n - length - 1 ] 
                else:
                    t_ret = combination[s_i][length] * factorial[length] * g_i * factorial[ n - length - 1 - 1 ]
                ret += t_ret * length

    return ret * 1.0 / factorial[n] + n

答案 1 :(得分:7)

这是与https://cs.stackexchange.com/questions/1076/how-to-approach-vertical-sticks-challenge相同的问题,我在那里的答案(比前面给出的更简单)是:

想象一个不同的问题:如果你必须在k个槽中放置n个相同高度的木棍,那么木棍之间的预期距离(以及第一个木棍和一个名义槽之间的预期距离{{ 1}},以及最后一个标记与名义广告位0)之间的预期距离为n+1,因为在(n+1)/(k+1)长度中有k+1个空白。

回到这个问题,一个特定的棒感兴趣的是多少棒(包括它自身)和高或高。如果这是n+1,那么之前的预期差距也是k

因此算法只是为每个棒找到这个值并加上期望值。例如,从(n+1)/(k+1)的高度开始,高度大于或等于的横杆数量为3,2,5,3,3,4,1,2,因此预期为5,7,1,5,5,2,8,7

这很容易编程:例如R

中的一行
9/6+9/8+9/2+9/6+9/6+9/3+9/9+9/8 = 15.25

给出sample output in the original problem

中的值
V <- function(Y){(length(Y) + 1) * sum(1 / (rowSums(outer(Y, Y, "<=")) + 1) )}

答案 2 :(得分:1)

正确地说,我们可以为每根棍子独立解决问题。

设F(i,len)是排列数,来自标记i的光线正好是len 然后回答是

  

(Sum(by i,len)F(i,len)* len)/(n!)

剩下的就是计算F(i,len)。令a(i)为j的数量,即y_j <= y_i。 b(i) - 棒数,b_j> b_i。

为了获得长度为len的光线,我们需要有这样的情况。

B, l...l, O  
   len-1 times

O - 坚持#i。 B - 坚持更长的长度或开始。 l - 坚持高位,然后小于第i。

这给了我们两个案例:
1)B是开始,这可以P(a(i), len-1) * (b(i)+a(i)-(len-1))!方式实现 2)B是更大的棒,这可以用P(a(i), len-1)*b(i)*(b(i)+a(i)-len)!*(n-len)方式实现。

编辑:在(mul)中将b(i)更正为第二项,代替案例2中的(i)。