Наріжте піцу на однакові скибочки


16

Це те, що я думав, що це питання буде, перш ніж я повністю його прочитав.

Група гольфістів з кодом заходять у піцерію «Дев'ятнадцятий укус» і замовляють піцу. Він виходить неправильної форми, виготовлений з одиничних квадратів. Ваше завдання - допомогти їм розрізати їх на однакові скибочки. Тобто скибочки повинні мати точно однакову форму і розмір; їх можна обертати, але не відвертати / дзеркально. Наприклад, якщо вони є шматками тетрісу, вони повинні бути однакового типу, ви не можете використовувати як шматок L, так і J шматок.

Вхідні дані

Вам буде вказано кількість людей у ​​групі на першому рядку (завжди ціле число від 2 до 10 включно), а потім прямокутна матриця символів '' (пробіл) та '#', що представляють піцу. Усі символи "#" з'єднані через їх краї. Гарантована кількість символів "#" буде кратною кількості людей.

Вихідні дані

Ви повинні надрукувати одну і ту ж матрицю, кожен символ "#" замінюється цифрою від 0 до n-1 (n - кількість людей). Кожна цифра повинна позначати фрагмент. Форма зрізу повинна бути з'єднана через квадратні краї. Нумерація зрізів не повинна бути в певному порядку. Якщо існує кілька способів нарізки піци, будь-який з них є прийнятним.
Якщо неможливо розрізати піцу як потрібно, слід надрукувати рядок "Ні для вас піци!" замість цього.

Оцінка балів

Це код гольфу. Вашим балом буде кількість байтів у програмі. Символи будуть рахуватися через кодування 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 © Хобі Кальвіна
aditsu

Бонус за рішення гегекс.
недолік

Відповіді:


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

Безгольовий, задокументований код

Нижче - задокументований оригінальний код. Щоб зберегти розумність, я працював з повним вихідним кодом, і написав простий скрипт мініфікатора, щоб зняти заяви, як-от 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: Не можу переосмислити _ () у pizza.php у рядку 1"
aditsu

@aditsu: у версії для гольфу існує лише одна функція _ (). Ви випадково скопіювали код два рази?
Джейсон Сміт

Розмір файлу - 972, тому я не думаю, що код міг би поміщатися двічі. Код, який не має волі, здається, працює btw :)
aditsu

Я помітив, що у вас є define('_',98), чи це не конфлікт function _? Я не знаю php, тому я не можу сказати ...
aditsu

@aditsu: Гольф-код працює на моєму Mac з PHP 5.4.43, але, схоже, _ () є псевдонімом gettext () на інших платформах. Змінено мініфікатор, щоб уникнути _ () взагалі.
Джейсон Сміт
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.