C# 谷歌代码Jam 2013 R1B-钻石掉落

C# 谷歌代码Jam 2013 R1B-钻石掉落,c#,algorithm,C#,Algorithm,昨天“密码堵塞”有一个题为“掉落的钻石”的问题。可以找到全文,但总结如下: 钻石沿Y轴下落 如果一颗钻石与另一颗钻石点对点碰撞,则它有50/50的几率向右或向左滑动,前提是它没有被阻止这样做 如果阻止钻石向一个方向滑动,它将始终向另一个方向滑动 如果钻石在两个方向都被阻挡,它将停止并停留在阻挡钻石上 如果一颗钻石落到地上,它会把自己埋到一半,然后停下来 钻石的方向永远不会改变,即它会滑动或下沉,但不会翻滚 目标是找出一颗钻石停在给定坐标上的概率,假设N颗钻石落下 上述要求基本上可以归结为钻石

昨天“密码堵塞”有一个题为“掉落的钻石”的问题。可以找到全文,但总结如下:

  • 钻石沿Y轴下落
  • 如果一颗钻石与另一颗钻石点对点碰撞,则它有50/50的几率向右或向左滑动,前提是它没有被阻止这样做
  • 如果阻止钻石向一个方向滑动,它将始终向另一个方向滑动
  • 如果钻石在两个方向都被阻挡,它将停止并停留在阻挡钻石上
  • 如果一颗钻石落到地上,它会把自己埋到一半,然后停下来
  • 钻石的方向永远不会改变,即它会滑动或下沉,但不会翻滚
  • 目标是找出一颗钻石停在给定坐标上的概率,假设N颗钻石落下
上述要求基本上可以归结为钻石建造更大的金字塔,一层一层

我只想说,我还没有能够解决这个问题,使谷歌满意。我从问题描述中获得的示例是正确的,但在实际输入文件中失败。理想情况下,我希望看到一个匹配的输入和正确的输出文件,我可以用它来尝试找到我的错误。除此之外,我也欢迎对我的代码发表评论

通常,我的方法是找出需要多少层才能有一个包含坐标的层。一旦我知道我在看哪一层,我就可以确定一些与我们试图达到的层和点相关的值。例如,当这一层为空时,金字塔中有多少颗钻石,有多少颗钻石可以堆积在一边,然后其他钻石被强制以另一种方式堆积,有多少颗必须沿同一方向滑动才能到达所需的点,等等

然后我检查钻石掉落的数量是否使其无法到达该点(概率0),或者保证我们将覆盖该点(概率1)。面临的挑战是在可能的情况下,但不能保证。p> 对于中间地带,我首先检查我们的下降是否足以填满一个侧面,并迫使剩余的下降向相反方向滑动。原因是在这种情况下,我们可以保证一定数量的钻石会滑到每一侧,这减少了我们不得不担心的下降次数,并解决了当一侧满时概率变化的问题。示例:如果12颗钻石掉落,则保证外层的每一侧都有2颗或更多钻石,给定一侧是否有2颗、3颗或4颗取决于仅2颗掉落的结果,而不是落在该层的所有6颗掉落的结果

一旦我知道有多少滴与成功相关,以及为了达到这一点必须以相同的方式打破的数字,我就把必要的数字或更多的数字以相同的方式出现的概率加起来

正如我所说,我可以解决问题描述中的示例,但是我没有得到输入文件的正确输出。不幸的是,我无法找到任何东西告诉我正确的输出是什么,以便我可以将其与我得到的进行比较。这是我的代码(比赛结束后,我花了相当长的时间试图调整它以获得成功,并添加注释以避免迷失方向):

受保护字符串解算(字符串行)
{
string[]Inputs=Line.Split();
int N=int.Parse(输入[0]);
int X=int.Parse(输入[1]);
int Y=int.Parse(输入[2]);
int AbsX=X>=0?X:-X;
int SlideCount=AbsX+Y;//必须堆叠在所需层的一侧,以迫使其余水滴向另一侧滑动的数字。
int LayerCount=(SlideCount>1;//该层从零开始的索引是幻灯片计数的1/2
int TOTALLAYREMPTY=((图层*图层)=目标覆盖)
{//如果我们有足够的空投来保证目标被覆盖,概率是1
返回“1.0”;
}
else if(LayerDropsSlideCount?LayerDrops-SlideCount:0;//保证每边都有这么多

int CriticalDrops=LayerDrops-(BalancedDrops您的假设过于简单。您可以下载与我的解决方案相关的大型数据集的正确答案:

你必须计算所有可能占据你兴趣点的钻石组合。为此,我使用了以下公式:

你基本上必须:

  • 计算金字塔的高度(即计算固定菱形)
  • 计算可以在左侧或右侧自由移动的钻石数
  • 计算概率(二项系数之和)
对于后者和点Y,你可以应用这个公式来计算概率

如果您无法解决此问题,也不要担心,因为它非常困难。如果您想要我的PHP解决方案,请参阅:

请注意,如果点位于的固定棱锥内或固定棱锥外,则必须进行计算,还必须进行其他次要检查

<?php


set_time_limit(0);


$data = file('2bl.in',FILE_IGNORE_NEW_LINES);


$number = array_shift($data);

for( $i=0;$i<$number;$i++ ) {

    $firstLine = array_shift($data);
    $firstLine = explode(' ',$firstLine);


    $s = $firstLine[0];
    $x = $firstLine[1];
    $y = $firstLine[2];

    $s = calcCase( $s,$x,$y  );
    appendResult($i+1,$s);

}


function calcCase($s,$x,$y) {

    echo "S: [$s] P($x,$y)\n<br>";

    $realH = round(calcH($s),1);
    echo "RealHeight [$realH] ";

    $h = floor($realH);
    if (isEven($h))
        $h--;

    $exactDiamonds = progression($h);
    movableDiamonds($s,$h,$exactDiamonds,$movableDiamonds,$unfullyLevel);   


    $widthLevelPoint = $h-$y;


    $spacesX =  abs($x) - $widthLevelPoint;

    $isFull = (int)isFull($s,$exactDiamonds);



    echo "Diamonds: [$s], isFull [$isFull], Height: [$h], exactDiamonds [$exactDiamonds], movableDiamonds [$movableDiamonds], unfullyLevel [$unfullyLevel] <br> 
         widthlevel [$widthLevelPoint], 
         distance from pyramid (horizontal) [$spacesX]<br> ";


    if ($spacesX>1)
        return '0.0';

    $pointHeight = $y+1;


    if ($x==0 && $pointHeight > $h) {
        return '0.0';
    }


    if ($movableDiamonds==0) { 

        echo 'Fixed pyramid';

        if ( $y<=$h && abs($x) <= $widthLevelPoint )    
            return '1.0';
        else
            return '0.0';

    } 



    if ( !$isFull ) {

        echo "Pyramid Not Full ";


        if ($spacesX>0)
            return '0.0';


        if ($unfullyLevel == $widthLevelPoint)  
            return '0.5';


        else if ($unfullyLevel > $widthLevelPoint)
            return '0.0';


        else
            return '1.0';

    }


    echo "Pyramid full";


    if ($spacesX<=0)
        return '1.0';

    if ($movableDiamonds==0)
        return '0.0';




    if ( $movableDiamonds > ($h+1) ) {

        $otherDiamonds = $movableDiamonds - ($h+1);
        if ( $otherDiamonds - $pointHeight >= 0  ) {

            return '1.0';
        }


    }

    $totalWays = totalWays($movableDiamonds);
    $goodWays = goodWays($pointHeight,$movableDiamonds,$totalWays);

    echo "<br>GoodWays: [$goodWays], totalWays: [$totalWays]<br>";


    return sprintf("%1.7f",$goodWays / $totalWays);
}



function goodWays($pointHeight,$movableDiamonds,$totalWays) {


    echo "<br>Altezza punto [$pointHeight] ";

    if ($pointHeight>$movableDiamonds)
        return 0;


    if ( $pointHeight == $movableDiamonds )
        return 1;

    $good = sumsOfBinomial( $movableDiamonds, $pointHeight );

    return $good;
}

function totalWays($diamonds) {
    return pow(2,$diamonds);    
}


function sumsOfBinomial( $n, $k ) {

    $sum = 1;   //> Last element (n;n)
    for($i=$k;$i<($n);$i++) {

        $bc =  binomial_coeff($n,$i);
        //echo "<br>Binomial Coeff ($n;$i): [$bc] ";

        $sum += $bc;
    }

    return $sum;
}


// calculate binomial coefficient
function binomial_coeff($n, $k) {

  $j = $res = 1;

  if($k < 0 || $k > $n)
     return 0;
  if(($n - $k) < $k)
     $k = $n - $k;

  while($j <= $k) {
    $res = bcmul($res, $n--);
    $res = bcdiv($res, $j++);
  }

  return $res;

}

function isEven($n) {
    return !($n&1); 
}

function isFull($s,$exact) {
    return ($exact <= $s);
}

function movableDiamonds($s,$h,$exact,&$movableDiamonds,&$level) {

    $baseWidth = $h;
    $level=$baseWidth;

    //> Full pyramid
    if ( isFull($s,$exact) ) {
        $movableDiamonds = ( $s-$exact );
        return;
    }


    $movableDiamonds = $s;

    while( $level ) {

        //echo "<br> movable [$movableDiamonds] removing [$level] <br>" ;

        if ($level > $movableDiamonds)  
            break;

        $movableDiamonds = $movableDiamonds-$level;
        $level--;
        if ($movableDiamonds<=0)
            break;
    }

    return  $movableDiamonds;

}


function progression($n) {
    return (1/2 * $n *(1+$n) );
}

function calcH($s) {

    if ($s<=3)
        return 1;

    $sqrt = sqrt(1+(4*2*$s));
    //echo "Sqrt: [$sqrt] ";

    return ( $sqrt-1 ) / 2;
}





function appendResult($caseNumber,$string) {
    static $first = true;

    //> Cleaning file
    if ($first) {
        file_put_contents('result.out','');
        $first=false;
    }

    $to = "Case #{$caseNumber}: {$string}";
    file_put_contents( 'result.out' ,$to."\n",FILE_APPEND); 
    echo $to.'<br>';
}

您的假设过于简单。您可以下载与我的解决方案相关的大型数据集的正确答案:

你必须计算所有可能占据你兴趣点的钻石组合。为此,我使用了以下公式:

你基本上必须:

  • 计算金字塔的高度(即计算固定菱形)
  • 计算可以在左侧或右侧自由移动的钻石数
  • 计算概率(二项系数之和)
用后者和t
<?php


set_time_limit(0);


$data = file('2bl.in',FILE_IGNORE_NEW_LINES);


$number = array_shift($data);

for( $i=0;$i<$number;$i++ ) {

    $firstLine = array_shift($data);
    $firstLine = explode(' ',$firstLine);


    $s = $firstLine[0];
    $x = $firstLine[1];
    $y = $firstLine[2];

    $s = calcCase( $s,$x,$y  );
    appendResult($i+1,$s);

}


function calcCase($s,$x,$y) {

    echo "S: [$s] P($x,$y)\n<br>";

    $realH = round(calcH($s),1);
    echo "RealHeight [$realH] ";

    $h = floor($realH);
    if (isEven($h))
        $h--;

    $exactDiamonds = progression($h);
    movableDiamonds($s,$h,$exactDiamonds,$movableDiamonds,$unfullyLevel);   


    $widthLevelPoint = $h-$y;


    $spacesX =  abs($x) - $widthLevelPoint;

    $isFull = (int)isFull($s,$exactDiamonds);



    echo "Diamonds: [$s], isFull [$isFull], Height: [$h], exactDiamonds [$exactDiamonds], movableDiamonds [$movableDiamonds], unfullyLevel [$unfullyLevel] <br> 
         widthlevel [$widthLevelPoint], 
         distance from pyramid (horizontal) [$spacesX]<br> ";


    if ($spacesX>1)
        return '0.0';

    $pointHeight = $y+1;


    if ($x==0 && $pointHeight > $h) {
        return '0.0';
    }


    if ($movableDiamonds==0) { 

        echo 'Fixed pyramid';

        if ( $y<=$h && abs($x) <= $widthLevelPoint )    
            return '1.0';
        else
            return '0.0';

    } 



    if ( !$isFull ) {

        echo "Pyramid Not Full ";


        if ($spacesX>0)
            return '0.0';


        if ($unfullyLevel == $widthLevelPoint)  
            return '0.5';


        else if ($unfullyLevel > $widthLevelPoint)
            return '0.0';


        else
            return '1.0';

    }


    echo "Pyramid full";


    if ($spacesX<=0)
        return '1.0';

    if ($movableDiamonds==0)
        return '0.0';




    if ( $movableDiamonds > ($h+1) ) {

        $otherDiamonds = $movableDiamonds - ($h+1);
        if ( $otherDiamonds - $pointHeight >= 0  ) {

            return '1.0';
        }


    }

    $totalWays = totalWays($movableDiamonds);
    $goodWays = goodWays($pointHeight,$movableDiamonds,$totalWays);

    echo "<br>GoodWays: [$goodWays], totalWays: [$totalWays]<br>";


    return sprintf("%1.7f",$goodWays / $totalWays);
}



function goodWays($pointHeight,$movableDiamonds,$totalWays) {


    echo "<br>Altezza punto [$pointHeight] ";

    if ($pointHeight>$movableDiamonds)
        return 0;


    if ( $pointHeight == $movableDiamonds )
        return 1;

    $good = sumsOfBinomial( $movableDiamonds, $pointHeight );

    return $good;
}

function totalWays($diamonds) {
    return pow(2,$diamonds);    
}


function sumsOfBinomial( $n, $k ) {

    $sum = 1;   //> Last element (n;n)
    for($i=$k;$i<($n);$i++) {

        $bc =  binomial_coeff($n,$i);
        //echo "<br>Binomial Coeff ($n;$i): [$bc] ";

        $sum += $bc;
    }

    return $sum;
}


// calculate binomial coefficient
function binomial_coeff($n, $k) {

  $j = $res = 1;

  if($k < 0 || $k > $n)
     return 0;
  if(($n - $k) < $k)
     $k = $n - $k;

  while($j <= $k) {
    $res = bcmul($res, $n--);
    $res = bcdiv($res, $j++);
  }

  return $res;

}

function isEven($n) {
    return !($n&1); 
}

function isFull($s,$exact) {
    return ($exact <= $s);
}

function movableDiamonds($s,$h,$exact,&$movableDiamonds,&$level) {

    $baseWidth = $h;
    $level=$baseWidth;

    //> Full pyramid
    if ( isFull($s,$exact) ) {
        $movableDiamonds = ( $s-$exact );
        return;
    }


    $movableDiamonds = $s;

    while( $level ) {

        //echo "<br> movable [$movableDiamonds] removing [$level] <br>" ;

        if ($level > $movableDiamonds)  
            break;

        $movableDiamonds = $movableDiamonds-$level;
        $level--;
        if ($movableDiamonds<=0)
            break;
    }

    return  $movableDiamonds;

}


function progression($n) {
    return (1/2 * $n *(1+$n) );
}

function calcH($s) {

    if ($s<=3)
        return 1;

    $sqrt = sqrt(1+(4*2*$s));
    //echo "Sqrt: [$sqrt] ";

    return ( $sqrt-1 ) / 2;
}





function appendResult($caseNumber,$string) {
    static $first = true;

    //> Cleaning file
    if ($first) {
        file_put_contents('result.out','');
        $first=false;
    }

    $to = "Case #{$caseNumber}: {$string}";
    file_put_contents( 'result.out' ,$to."\n",FILE_APPEND); 
    echo $to.'<br>';
}
layer = floor( ( sqrt( 1 + 8 * diamonds ) + 1 ) / 4 )
overflow = diamonds - layer * ( 2 * layer - 1 )
P( nr ) = binomial_coefficient( overflow, k ) * pow( 0.5, overflow )
p = 0.0
for i in range( nr + 1 ):
    p += pow( 0.5, overflow - i ) * binomial_coefficient( overflow - i - 1, nr - i )