将比萨切成相同的切片


16

在我完全阅读它之前,这就是我认为的问题

一群有经验的高尔夫球手走进第十九叮咬比萨店,点了一个披萨。它呈不规则形状,由单位正方形组成。您的任务是帮助他们将其切成相同的切片。也就是说,切片必须具有完全相同的形状和大小。它们可以旋转,但不能翻转/镜像。例如,如果它们是俄罗斯方块,它们必须是同一种,则不能同时使用L片和J片。

输入值

在第一行中将为您提供组中的人数(总是2到10之间的整数,包括2和10),然后是矩形的矩阵,由''(空格)和'#'字符组成,代表披萨。所有“#”字符都通过其边缘连接。“#”字符的数量保证为人数的倍数。

输出量

您应该打印相同的矩阵,每个'#'字符替换为从0到n-1的数字(n是人数)。每个数字应标记一个切片。切片形状必须通过正方形边缘连接。切片编号不需要按任何特定顺序进行。如果有多种切比萨饼的方法,那么任何一种都是可以接受的。
如果无法按照要求切比萨饼,则应打印字符串“ No pizza for you!”。代替。

计分

这是代码高尔夫。您的分数将是程序中的字节数。字符将通过其UTF-8编码进行计数。最低分获胜。

例子

输入:

3
 #  
### 
####
   #

输出:

 0  
100 
1122
   2

输入:

4
###
# #
###

输出:

001
2 1
233

输入:

2
#    #
######

输出:

No pizza for you!

输入:

5
    #  
   ####
  #####
 ##### 
#####  
####   
  #    

输出:

    0  
   1000
  21110
 32221 
43332  
4443   
  4    

输入:

4
   #   
 ####  
###### 
  #####
  #### 

输出:

   0   
 1000  
111203 
  12233
  2233 

要求

  • 您应该编写一个完整的程序,该程序可以从标准输入读取并写入标准输出。
  • 该程序必须可以使用免费提供的软件在Linux中运行。
  • 您的程序应在一台现代化的计算机上在不到1分钟的时间内完成上述每个示例。
  • 没有标准漏洞。

3
第十九撕咬:^)
FryAmTheEggman

@FryAmTheEggman©Calvin's Hobbies
aditsu 2015年

正则表达式解决方案的奖励。
瑕疵的

Answers:


3

PHP代码, 1808 971字节

在PHP中快速而肮脏的实现。首先蛮力所有可能的切片形状,然后蛮力所有切片的所有位置和方向。

用法: cat pizza.txt | php pizza.php

编辑:通过使用递归而不是嵌套循环的重演算法,将代码大小减少了45%以上。但是,这会消耗内存(和比萨饼的;-)。大于8x8的披萨可能会耗尽内存。嵌套循环变量可以轻松处理任何大小,但是是代码大小的两倍。

<?php define('A',98);$n=fgets(STDIN);$d=array();$m=$u=str_pad('',A,'+');$s=0;while($g=fgets(STDIN)){$g=rtrim($g);assert(strlen($g)<=A-2);$s++;$m.='+'.str_pad(rtrim($g),A-2,' ').'+';for($l=0;$l<strlen($g);$l++)if($g[$l]=='#')$d[]=$s*A+$l+1;}$m.=$u;$r=count($d)/$n;x(reset($d),array(array()),0,0,0,0);die('No pizza for you!');function x($e,$c,$b,$a,$q,$t){global$r,$m,$d;$h=$a*A+$b;if(!in_array($e+$h,$d))return;if(in_array($h,$c[0]))return;$c[0][]=$h;$c[1][]=$b*A-$a;$c[2][]=-$a*A-$b;$c[3][]=-$b*A+$a;if(count($c[0])<$r)do{x($e,$c,$b+1,$a,$b,$a);x($e,$c,$b,$a+1,$b,$a);x($e,$c,$b-1,$a,$b,$a);x($e,$c,$b,$a-1,$b,$a);$v=($b!=$q||$a!=$t);$b=$q;$a=$t;}while($v);else w($c,$m,0,reset($d),0);}function w(&$p,$f,$o,$e,$i){global$n,$d;foreach($p[$i]as$h){$j=$e+$h;if(!isset($f[$j])||$f[$j]!='#')return;$f[$j]=chr(ord('0')+$o);}if(++$o==$n){for($k=A;$k<strlen($f)-A;$k++)if($k%A==A-1)echo PHP_EOL;else if($k%A)echo$f[$k];exit;}foreach($d as$j)for($i=0;$i<4;$i++)w($p,$f,$o,$j,$i);}

未经记录的代码

下面是记录的原始代码。为了保持理智,我使用了完整的源代码,并编写了一个简单的minifier脚本来删除诸如assert()和的语句error_reporting(),删除不必要的括号,重命名变量,函数和常量,以生成上述代码。

<?php
error_reporting(E_ALL) ;

// Width of each line of pizza shape.
// Constant will be reduced to single character by minifier,
// so the extra cost of the define() will be gained back.
define('WIDTH', 98) ;

// Read number of slices
$nrSlices = fgets(STDIN) ;

// Read pizza shape definition and 
// convert to individual $positionList[]=$y*width+$x and
// linear (1D) $pizzaShape[$y*WIDTH+$x] with protective border around it.
//
// WARNING: assumes maximum pizza width of WIDTH-2 characters!
$positionList = array() ;
$pizzaShape = $headerFooter = str_pad('', WIDTH, '+') ;
$y = 0 ;
while ($line = fgets(STDIN))
{  $line = rtrim($line) ;
   assert(strlen($line) <= WIDTH-2) ;
   $y++ ;
   $pizzaShape .= '+'.str_pad(rtrim($line), WIDTH-2, ' ').'+' ;
   for ($x = 0 ; $x < strlen($line) ; $x++)
   {  if ($line[$x] == '#') $positionList[] = $y*WIDTH + $x+1 ;
   }
}
$pizzaShape .= $headerFooter ;

// Determine size of a slice
$sliceSize = count($positionList)/$nrSlices ;

// Build all possible slice shapes. All shapes start with their first part at 
// the top of the pizza, and "grow" new parts in all directions next to the 
// existing parts. This continues until the slice has the full size. This way
// we end up with all shapes that fit at the top of the pizza.
//
// The shape is defined as the offsets of the parts relative to the base 
// position at the top of the pizza. Offsets are defined as linear offsets in
// the 1-D $pizzaShape string.
//
// For efficiency, we keep track of all four possible rotations while building
// the slice shape.
//
growSlice(reset($positionList), array(array()), 0, 0, 0, 0) ;
die('No pizza for you!') ;

function growSlice($basePosition, $shapeDeltas, $dx, $dy, $prevDx, $prevDy)
{  global $sliceSize, $pizzaShape, $positionList ;

   // Check validity of new position
   // Abort if position is not part of pizza, or 
   // if position is already part of slice
   $delta = $dy*WIDTH + $dx ;
   if (!in_array($basePosition+$delta, $positionList)) return ;
   if (in_array($delta, $shapeDeltas[0])) return ;

   // Add all four rotations to shapeDeltas[]
   $shapeDeltas[0][] = $delta ;
   $shapeDeltas[1][] = $dx*WIDTH - $dy ;
   $shapeDeltas[2][] = -$dy*WIDTH - $dx ;
   $shapeDeltas[3][] = -$dx*WIDTH + $dy ;

   // Have we built a full slice shape?
   if (count($shapeDeltas[0]) < $sliceSize) 
   {  // Grow shape either at current position or at previous position
      do
      {  growSlice($basePosition, $shapeDeltas, $dx+1, $dy,   $dx, $dy) ;
         growSlice($basePosition, $shapeDeltas, $dx,   $dy+1, $dx, $dy) ;
         growSlice($basePosition, $shapeDeltas, $dx-1, $dy,   $dx, $dy) ;
         growSlice($basePosition, $shapeDeltas, $dx,   $dy-1, $dx, $dy) ;
         $retry = ($dx != $prevDx || $dy != $prevDy) ;
         $dx = $prevDx ;
         $dy = $prevDy ;
      } while ($retry) ;
   } else
   {  // Try to cover the entire pizza by translated and rotated instances of
      // the slice shape.
      fitSlice($shapeDeltas, $pizzaShape, 0, reset($positionList), 0) ;
   }
}

function fitSlice(&$shape, $pizza, $id, $basePosition, $rotation)
{  global $nrSlices, $positionList ;

   // Try to fit each part of the slice onto the pizza. If the part falls
   // outsize the pizza, or overlays another slice we reject this position
   // and rotation. If it fits, we mark the $pizza[] with the slice $id.
   foreach ($shape[$rotation] as $delta)
   {  $position = $basePosition + $delta ;
      if (!isset($pizza[$position]) || $pizza[$position] != '#') return ;
      $pizza[$position] = chr(ord('0')+$id) ;
   }

   // If $nrSlices slices have been fitted, we have found a valid solution!
   // In that case, we display the solution and quit.
   if (++$id == $nrSlices)
   {  for ($pos = WIDTH ; $pos < strlen($pizza)-WIDTH ; $pos++)
      {  if ($pos % WIDTH == WIDTH-1) echo PHP_EOL ;
         else if ($pos % WIDTH) echo $pizza[$pos] ;
      }
      exit ;
   }

   // The current slice did fit, but we have still more slices to fit.
   // Try all positions and rotations for the next slice.
   foreach ($positionList as $position)
   {  for ($rotation = 0 ; $rotation < 4 ; $rotation++)
      {  fitSlice($shape, $pizza, $id, $position, $rotation) ;
      }
   }
}

我收到“ PHP致命错误:无法在第1行上在pizza.php中重新声明_()”
aditsu

@aditsu:高尔夫版本中只有一个函数_()。您是否偶然将代码复制粘贴两次?
杰森·史密斯

文件大小为972,所以我认为代码不能容纳两次。顺便说一句,似乎没有效果的代码是可行的:)
aditsu

我注意到你有define('_',98),这不矛盾function _吗?我不知道php,所以我不知道...
aditsu

@aditsu:在我的Mac上使用PHP 5.4.43的情况下,经过优化的代码可以正常工作,但是_()在其他平台上似乎是gettext()的别名。更改了缩小符,以完全避免_()。
杰森·史密斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.