Допоможи мені розібрати свої шкарпетки!


30

У мене є купа чистих шкарпеток, які я хочу сортувати по парах. На жаль, я можу брати шкарпетки лише з будь-якого кінця ворсу, а не з середини. Крім того, я можу видаляти шкарпетки з ворсу тільки за один раз. Моя стратегія полягає в тому, щоб спочатку розділити купу на одну або кілька менших паль. Я думаю, що деякі приклади це стануть зрозумілими. Я буду представляти кожен шкарпетку як натуральне число (відповідні цілі числа вказують рівні шкарпетки).

Якщо початкова купа шкарпеток є

1 2 3 3 2 1

тоді мені не потрібно робити ніяких розколів. Я можу зняти обидва 1шкарпетки, потім обидва 2шкарпетки, потім обидва 3шкарпетки.

Якщо замість цього початковий стоп

1 2 3 2 3 1

тоді я повинен спершу розділити його, тому що я не зможу з’єднати всі шкарпетки, просто видаливши їх з кінця. Одна з можливостей - це розділити його на дві палі

1 2 3 and 2 3 1

Тепер я можу зняти 1шкарпетки, залишаючи 2 3 and 2 3, слідом за 3шкарпетками, залишаючи 2 and 2і нарешті 2шкарпетки.

Ваша робота

З огляду на початкову купу шкарпеток, напишіть програму, яка розділить її на менші палі, що дозволить мені сортувати шкарпетки. Ваша програма повинна розділити купу на найменшу кількість можливих паль (якщо є кілька кращих рішень, вам потрібно знайти лише одне).

Вхід буде надано у вигляді списку, обмеженого рядка або іншої зручної форми. Він буде містити лише цілі числа між 1і деяким максимальним значенням n, при цьому кожне ціле число трапляється рівно двічі.

Вихід повинен складатися з вхідного списку, розділеного на менші списки, поданого в будь-якій зручній формі.

Приклади

Input             Sample Output
1 1               1 1
1 2 1 2           1; 2 1 2
1 3 2 4 3 2 1 4   1 3 2; 4 3 2 1 4
1 2 3 4 3 4 1 2   1; 2 3; 4 3 4 1 2
1 1 2 2 3 3       1 1 2; 2 3 3
4 3 4 2 2 1 1 3   4 3 4 2; 2 1 1 3

Зауважте, що це не єдиний дозволений вихід для більшості цих входів. Для другого випадку, наприклад, результати 1 2; 1 2або 1 2 1; 2також будуть прийняті.

Дякуємо Sp3000 за кілька тестових пропозицій!

Я ненавиджу витрачати довгий час на сортування одягу, тому зробіть свій код якомога коротшим. Найкоротша відповідь у байтах виграє!

Примітки

  • Мені не хочеться дивитися за шкарпетку, щоб побачити, чи є його відповідна пара, тому брати обидва шкарпетки в парі з одного кінця не дозволяється. Наприклад, якщо ворс 1 1 2 2тоді, ви не зможете залишити його як одну купу і взяти обидва 1шкарпетки з лівого кінця.

5
Я можу привітатись до КПКГ Кармейстер. Це дуже хороший перший виклик +1.
Логічний лицар

1
Ласкаво просимо до PPCG! Це дуже гарне перше питання. Хоча це питання, як видається, не має жодних серйозних проблем, ми радимо користувачам використовувати пісочницю, щоб отримувати відгуки про свої виклики, перш ніж надсилати їх.
Мего

Так 123213можна поділити на 1; 23; 213( 1; 23; 213-> 1; 2; 21-> ; 2; 2)?
Р. Кап

@Mego Дякую! Я обов'язково буду це робити надалі. @ R.Kap Це був би вірний спосіб розділити його, але відповідь повинна дати розщеплення, яке розбиває його на найменшу кількість можливих паль. Оскільки можна розділити, 123213використовуючи лише дві палі, у Вашій відповіді доведеться дати один з двох стовпів.
Кармейстер

1
@ven Я не зовсім впевнений, що я розумію ваше запитання, але шкарпетки, які можна взяти, - це ті, хто знаходиться на початку кожної стопки, і ті, хто знаходиться в кінці кожної купи.
Кармейстер

Відповіді:


6

Pyth, 25 байт

hf!u #-R.-F{BhMs_BMGGT)./

Тестовий набір

Пояснення:

hf!u #-R.-F{BhMs_BMGGT)./
                       ./    Form all partitions (implicitly) of the input.
 f                           Filter the permutations on
   u                 T)      Run the following function on the partition
                             until it reaches a fixed point:
                _BMG         Bifurcate the lists on reversal
               s             Concatenate
             hM              Take the first element of each list. 
                             These elements are all the ones on the ends of lists.
           {B                Bifurcate on deduplication
        .-F                  Bagwise subtraction.
                             Only elements repeated in ends of lists remain.
      -R            G        Remove these elements from each list.
   ' #'                      Filter out empty lists.
  !                          Negate. Only an empty list as fixed point succeeds.
h                            Output the first successful partition.

5

JavaScript (ES6), 329

Непросте завдання для мови, яка не має вбудованої комбінаторики.

Напевно, ошатно більш грізний.

Примітка: усі розділи мають розмір принаймні 2, оскільки розділ з одним елементом завжди менш корисний.

Example: [1] [2 3 4] // can take 1 or 2 or 4  
Better: [1 2] [3 4] // can take 3 too  
a=>{G=(v,i,u=v)=>{if(i--){for(;r[i]=--u;)if(G(u,i))return 1;}else for(w=[...r,n=l].map((x,i)=>a.slice(z,z=x-~i),z=0),y=w.join`;`;w.map(b=>[0,1].map(q=>(x=b[q*=~-b.length])&&(t[x]?([c,p]=t[x],n-=2,p?c.pop():c.shift(),q?b.pop():b.shift()):t[x]=[b,q])),c=0,t=[]),c;)if(!n)return 1};for(l=a.length,r=[],k=0;!G(l-k-1,k);k++);return y}

Пояснення частинами

(це надмірно багатослівно, але мені було важко пояснити - врешті-решт пропустити, щоб "скласти все разом")

Рекурсивна функція для перерахування всіх можливих розщеплень масиву

// v: array length
// i number of splits
// fill the global array r that must exists
G=(v,i,u=v)=>
{
  if(i--)
  {
    for(;r[i]=--u;)
      G(u,i)
  }
  else
  {
    // the current split position are in r, ready to use
    // for instance...
    parts = [...r,a.length].map(x=>a.slice(z,z=x),z=0)
    console.log(r, parts)
  }
};

r=[]
a=['A','B','C','D']
G(4, 2)

// output in console (firebug)
[2, 3] [["A", "B"], ["C"], ["D"]]
[1, 3] [["A"], ["B", "C"], ["D"]]
[1, 2] [["A"], ["B"], ["C", "D"]]

Тепер мені потрібні розділи розміром 2 або більше, тому я повинен використовувати цю функцію з рівномірно різними параметрами. Параметр v - "розмір масиву - кількість бажаних розділів - 1". Тоді я повинен будувати перегородки дещо по-іншому.

// Same call (4,2), same r, but the array b is of size 7
part = [...r,b.length].map((x,i)=>
          b.slice(z,z=x+i+1) // add 1 more element to each partition
       ,z=0))
// output in console (firebug) 
[2, 3] [["A", "B", "C"], ["D", "E"], ["F", "G"]]
[1, 3] [["A", "B"], ["C", "D", "E"], ["F", "G"]]
[1, 2] [["A", "B"], ["C", "D"], ["E", "F", "G"]]

Отже, я можу перерахувати список розділів без розколу, 1 розбиття, 2 розбиття тощо. Коли я знайду робочий розділ, я зупинюсь та виведу знайдений результат.

Щоб перевірити, скануйте список розділів, відзначте значення на початку та в кінці кожного, якщо знайдене відновлене значення, тоді видаліть його. Повторіть, поки нічого не можна буде видалити, нарешті: якщо всі пари були видалені, тоді цей розділ хороший.

t = []; // array to note the repeated values
// t[x] == [
//           subarray holding value x, 
//           position of value x (I care zero or nonzero)
//         ]
n = a.length // counter start, must reach 0
// remember part just in case, because this check will destroy it 
result = part.join(';') // a string representation for return value
do
{
  // in the golfed code there is a forr loop
  // all this body is inside the for condition
  c = 0; // init c to a falsy, if a pair is found c becomes truthy
  part.forEach(b=> // b: array, current partition
    [0,1].forEach(q=> ( // exec for 0 (start), 1 (end)
      q *= b.length-1, // now q is the correct index
      x = b[q]) // x is the value at start or end
      x && ( // b could be empty, check that x is not 'undefined'
        t[x] ? // is there a value in t at position x?
           ( // yes, remove the pair
             n-=2, // pair found, decrement counter
             [c, p] = t[x], // get stored array and position
             p ? c.pop() : c.shift(), // remove from c at start or end
             q ? b.pop() : b.shift()  // remove twin value from b
           )
           : // no, remember the value in t
             t[x] = [b, q]
    )) // end [0,1].forEach
  ) // end part.forEach
}
while (c) // repeat until nothing can be removed
if(!n) return 1 // wow, result found (in 'result' variable)

Тоді відсутня частина - це лише цикл, що викликає функцію G, збільшуючи кількість розділів. Вихід із циклу, коли знайдений результат.

Покладіть все це разом

F=a=>{
  G=(v,i,u=v)=>{
    if (i--)
    {
      for(; r[i]=--u; )
        if (G(u,i)) 
          return 1;
    }
    else
    {
      w = [...r,n=l].map((x,i)=>a.slice(z, z = x-~i), z = 0);
      y = w.join`;`;
      for(; // almost all the for body is inside the condition
        w.map(b=>
          [0,1].map(q=>
            (x=b[q*=~-b.length])
             &&(t[x]
                ?([c,p]=t[x],n-=2,
                   p?c.pop():c.shift(),
                   q?b.pop():b.shift())
                :t[x]=[b,q])) // end [0,1].map
          ,c=0,t=[] // init variables for w.map
        ),c; // the loop condition is on c
      )
        if(!n)return 1 // this is the for body
    }
  };
  for(l = a.length, r = [], k = 0; !G(l-k-1, k); k++);
  return y
}

Тест

F=a=>{G=(v,i,u=v)=>{if(i--){for(;r[i]=--u;)if(G(u,i))return 1;}else for(w=[...r,n=l].map((x,i)=>a.slice(z,z=x-~i),z=0),y=w.join`;`;w.map(b=>[0,1].map(q=>(x=b[q*=~-b.length])&&(t[x]?([c,p]=t[x],n-=2,p?c.pop():c.shift(),q?b.pop():b.shift()):t[x]=[b,q])),c=0,t=[]),c;)if(!n)return 1};for(l=a.length,r=[],k=0;!G(l-k-1,k);k++);return y}

console.log=x=>O.textContent+=x+'\n'

TestData=[[1,1],[1,2,1,2],[1,3,2,4,3,2,1,4],[1,2,3,4,3,4,1,2],[1,1,2,2,3,3],[4,3,4,2,2,1,1,3]]

TestData.forEach(t=>console.log(t+' -> '+F(t)))

function RandomTest() {
  var l=I.value*2
  var a=[...Array(l)].map((_,i)=>1+i/2|0)
  a.map((v,i)=>a[a[i]=a[j=0|i+Math.random()*(a.length-i)],j]=v) // shuffle
  Q.textContent=a+''+'\n\n'+F(a).replace(/;/g, ';\n') // better readability
}
Base test
<pre id=O></pre>
Random test. Number of pairs: <input id=I value=15><button onclick="RandomTest()">-></button>
<pre id=Q></pre>

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.