Bantu aku menyortir kaus kakiku!

30

Saya memiliki setumpuk kaus kaki bersih yang ingin saya pisahkan menjadi pasangan. Sayangnya, saya hanya bisa mengambil kaus kaki dari kedua ujung tumpukan, bukan di tengah. Lebih lanjut, saya hanya dapat menghapus kaus kaki dari tumpukan pasangan yang serentak. Strategi saya adalah pertama membagi tumpukan menjadi satu atau lebih tumpukan yang lebih kecil. Saya pikir beberapa contoh akan memperjelas ini. Saya akan mewakili setiap kaus kaki sebagai bilangan bulat positif (bilangan bulat yang cocok menunjukkan kaus kaki yang sama).

Jika tumpukan kaus kaki awal adalah

1 2 3 3 2 1

maka saya tidak perlu melakukan pemisahan. Saya bisa menghapus kedua 1kaus kaki, lalu kedua 2kaus kaki, lalu kedua 3kaus kaki.

Jika bukan tumpukan awal adalah

1 2 3 2 3 1

maka saya harus membaginya terlebih dahulu karena saya tidak akan bisa memasangkan semua kaus kaki hanya dengan melepasnya dari ujungnya. Satu kemungkinan adalah membaginya menjadi dua tumpukan

1 2 3 and 2 3 1

Sekarang saya bisa melepas 1kaus kaki, pergi 2 3 and 2 3, diikuti 3kaus kaki, pergi 2 and 2, dan akhirnya 2kaus kaki.

Pekerjaan Anda

Mengingat tumpukan kaus kaki awal, tulis sebuah program yang akan membaginya menjadi tumpukan yang lebih kecil yang memungkinkan saya untuk menyortir kaus kaki. Program Anda harus membagi tumpukan menjadi jumlah tiang paling sedikit yang mungkin (jika ada beberapa solusi terbaik, Anda hanya perlu menemukan satu).

Input akan diberikan sebagai daftar, string yang dibatasi, atau bentuk lain yang sesuai. Ini hanya akan berisi bilangan bulat antara 1dan beberapa nilai maksimum n, dengan setiap bilangan bulat terjadi tepat dua kali.

Output harus terdiri dari daftar input yang dipecah menjadi daftar yang lebih kecil, diberikan dalam bentuk apa pun yang mudah.

Contohnya

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

Perhatikan bahwa ini bukan satu-satunya output yang diizinkan untuk sebagian besar input ini. Untuk kasus kedua, misalnya, output 1 2; 1 2atau1 2 1; 2 juga akan diterima.

Terima kasih kepada Sp3000 untuk beberapa saran pengujian!

Saya benci menghabiskan waktu lama menyortir pakaian saya, jadi buat kode Anda sesingkat mungkin. Jawaban terpendek dalam byte menang!

Catatan

  • Saya tidak ingin harus melihat ke belakang kaus kaki untuk melihat apakah ada pasangan yang cocok, jadi mengambil kedua kaus kaki dengan sepasang dari ujung yang sama tidak diperbolehkan. Misalnya jika tumpukan itu 1 1 2 2maka Anda tidak akan dapat meninggalkannya sebagai satu tumpukan dan mengambil kedua 1kaus kaki dari ujung kiri.
Carmeister
sumber
5
Boleh saya ucapkan selamat datang di PPCG Carmeister. Ini tantangan pertama +1 yang sangat bagus.
Logic Knight
1
Selamat datang di PPCG! Ini pertanyaan pertama yang sangat bagus. Meskipun pertanyaan ini tampaknya tidak memiliki masalah besar, kami mendorong pengguna untuk menggunakan Sandbox untuk menerima umpan balik tentang tantangan mereka sebelum mempostingnya.
Mego
Jadi 123213bisa dipecah menjadi 1; 23; 213( 1; 23; 213-> 1; 2; 21-> ; 2; 2)?
R. Kap
@Mego, terima kasih! Saya pasti akan melakukan itu di masa depan. @ R.Kap Itu akan menjadi cara yang sah untuk membaginya, tetapi jawabannya harus memberikan pemisahan yang membaginya menjadi jumlah tumpukan terkecil yang mungkin. Karena dimungkinkan untuk membagi 123213hanya menggunakan dua tumpukan, jawaban Anda harus memberikan satu dari dua tumpukan tumpukan.
Carmeister
1
@ bahkan saya tidak sepenuhnya yakin saya mengerti pertanyaan Anda, tetapi kaus kaki yang tersedia untuk diambil adalah yang ada di awal setiap tumpukan dan yang ada di akhir setiap tumpukan.
Carmeister

Jawaban:

6

Pyth, 25 byte

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

Suite uji

Penjelasan:

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.
isaacg
sumber
5

JavaScript (ES6), 329

Bukan tugas yang mudah untuk bahasa yang tidak memiliki kombinatorik bawaan.

Mungkin golf lebih ringan.

Catatan: semua partisi setidaknya berukuran 2, karena partisi dengan elemen tunggal selalu kurang bermanfaat.

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}

Penjelasan dalam bagian-bagian

(Ini terlalu bertele-tele, tapi saya merasa sulit untuk menjelaskan - akhirnya melompat ke "menyatukan semuanya")

Fungsi rekursif untuk menghitung semua kemungkinan pemisahan array

// 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"]]

Sekarang, saya perlu partisi dengan ukuran 2 atau lebih, jadi saya harus menggunakan fungsi ini dengan parameter sligtly berbeda. Parameter v adalah "ukuran array - jumlah partisi yang diinginkan - 1". Maka saya harus membangun partisi dengan cara yang sedikit berbeda.

// 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"]]

Jadi, saya dapat menyebutkan daftar partisi tanpa split, 1 split, 2 splits dan sebagainya. Ketika saya menemukan partisi yang berfungsi, saya akan berhenti dan menampilkan hasil yang ditemukan.

Untuk memeriksa, memindai daftar partisi, catat nilainya pada awal dan akhir dari masing-masing, jika menemukan nilai yang direplikasi kemudian hapus. Ulangi sampai tidak ada yang bisa dihapus, akhirnya: jika semua pasangan dihapus maka partisi ini baik.

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)

Kemudian, bagian yang hilang hanyalah loop caling fungsi G yang meningkatkan jumlah partisi. Loop keluar saat hasilnya ditemukan.

Kumpulkan semuanya

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
}

Uji

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>

edc65
sumber