Corte uma pizza em fatias idênticas

16

Era isso que eu pensava que essa pergunta seria antes de ler completamente.

Um grupo de jogadores de código entra na The Nineteenth Bite Pizzeria e pede uma pizza. Ele vem em uma forma irregular, feita de quadrados unitários. Sua tarefa é ajudá-los a cortá-lo em fatias idênticas. Ou seja, as fatias devem ter exatamente a mesma forma e tamanho; eles podem ser girados, mas não invertidos / espelhados. Por exemplo, se são peças de Tetris, devem ser do mesmo tipo, você não pode usar tanto uma peça L quanto uma peça J.

Entrada

Você receberá o número de pessoas no grupo na primeira linha (sempre um número inteiro de 2 a 10, inclusive), seguido por uma matriz retangular de caracteres '' (espaço) e '#', representando a pizza. Todos os caracteres '#' são conectados pelas bordas. É garantido que o número de caracteres '#' seja um múltiplo do número de pessoas.

Resultado

Você deve imprimir a mesma matriz, com cada caractere '#' substituído por um dígito de 0 a n-1 (n sendo o número de pessoas). Cada dígito deve marcar uma fatia. A forma da fatia deve ser conectada pelas bordas quadradas. A numeração da fatia não precisa estar em nenhuma ordem específica. Se houver várias maneiras de cortar a pizza, qualquer uma delas é aceitável.
Se não for possível cortar a pizza conforme necessário, imprima a sequência "Sem pizza para você!" em vez de.

Pontuação

Isso é código de golfe. Sua pontuação será o número de bytes no programa. Os caracteres serão contados através da codificação UTF-8. Menor pontuação ganha.

Exemplos

Entrada:

3
 #  
### 
####
   #

Resultado:

 0  
100 
1122
   2

Entrada:

4
###
# #
###

Resultado:

001
2 1
233

Entrada:

2
#    #
######

Resultado:

No pizza for you!

Entrada:

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

Resultado:

    0  
   1000
  21110
 32221 
43332  
4443   
  4    

Entrada:

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

Resultado:

   0   
 1000  
111203 
  12233
  2233 

Exigências

  • Você deve escrever um programa completo que leia da entrada padrão e grave na saída padrão.
  • O programa deve ser executável no Linux usando software disponível gratuitamente.
  • Seu programa deve concluir cada um dos exemplos acima em menos de 1 minuto em um computador moderno.
  • Sem brechas padrão.
aditsu
fonte
3
A décima nona mordida : ^)
FryAmTheEggman
@FryAmTheEggman © Calvin's Hobbies
aditsu
Bônus para soluções regex.
flawr

Respostas:

3

Código PHP, 1808 971 bytes

Implementação rápida e suja em PHP. Primeira força bruta em todas as formas possíveis de fatias, depois força bruta em todas as posições e orientações das fatias.

Uso: cat pizza.txt | php pizza.php

Editar: reduziu o tamanho do código em mais de 45% ao retroceder o algoritmo usando recursão em vez de loops aninhados. No entanto, isso consome memória (e pizzas ;-)). As pizzas maiores que 8x8 provavelmente ficarão sem memória. A variante de loop aninhado pode lidar facilmente com qualquer tamanho, mas é duas vezes o tamanho do código.

<?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);}

Código documentado e não-jogado

Abaixo está o código original documentado. Para manter minha sanidade mental, trabalhei com o código fonte completo e escrevi um script minificador simples para remover instruções como assert()e error_reporting()remover colchetes desnecessários, renomear variáveis, funções e constantes para gerar o código golfado acima.

<?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) ;
      }
   }
}
Jason Smith
fonte
Estou recebendo "Erro fatal do PHP: não é possível redefinir _ () no pizza.php na linha 1"
aditsu
@ aditsu: existe apenas uma função _ () na versão golfed. Você acidentalmente copiou e colou o código duas vezes?
Jason Smith
O tamanho do arquivo é 972, então não acho que o código possa caber duas vezes. O código ungolfed parece funcionar btw :)
aditsu
Notei que você tem define('_',98), isso não entra em conflito function _? Eu não sei php, então eu não posso dizer ...
aditsu 17/09/15
@aditsu: O código golfed funciona bem no meu Mac com o PHP 5.4.43, mas parece que _ () é um apelido para gettext () em outras plataformas. Minifier alterado para evitar _ () completamente.
Jason Smith