ช่วยฉันจัดเรียงถุงเท้าของฉัน!


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
ฉันขอพูดยินดีต้อนรับสู่ PPCG Carmeister นี่เป็นความท้าทายแรกที่ดีมาก +1
Logic Knight

1
ยินดีต้อนรับสู่ PPCG! นี่เป็นคำถามแรกที่ดีมาก แม้ว่าคำถามนี้จะไม่ปรากฏว่ามีปัญหาสำคัญ แต่เราสนับสนุนให้ผู้ใช้ใช้Sandboxเพื่อรับคำติชมเกี่ยวกับความท้าทายของพวกเขาก่อนโพสต์
Mego

ดังนั้น123213สามารถแบ่งออกเป็น1; 23; 213( 1; 23; 213-> 1; 2; 21-> ; 2; 2)?
R. Kap

@Mego ขอบคุณ! ฉันจะทำอย่างนั้นในอนาคต @ R.Kap นั่นจะเป็นวิธีที่ถูกต้องในการแยกมัน แต่คำตอบควรให้การแบ่งที่แยกมันออกเป็นกองเล็กที่สุดเท่าที่จะเป็นไปได้ เนื่องจากเป็นไปได้ที่จะแยก123213โดยใช้เพียงสองกองคำตอบของคุณจะต้องแยกหนึ่งในสองกอง
Carmeister

1
@ แม้ฉันไม่แน่ใจว่าฉันเข้าใจคำถามของคุณอย่างถ่องแท้ แต่ถุงเท้าที่มีให้เลือกคือถุงเท้าที่จุดเริ่มต้นของแต่ละกองและท้ายของแต่ละกอง
Carmeister

คำตอบ:


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

ไม่ใช่เรื่องง่ายสำหรับภาษาที่ไม่มี combinatorics ในตัว

น่าจะเป็นสนามกอล์ฟที่ sligthly

หมายเหตุ: พาร์ติชันทั้งหมดมีขนาดอย่างน้อย 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}

คำอธิบายในส่วนต่าง ๆ

(มัน verbose มากเกินไป แต่ฉันพบว่ามันยากที่จะอธิบาย - ในที่สุดก็ข้ามไปที่ "ทำให้มันเข้าด้วยกัน")

ฟังก์ชันเรียกซ้ำเพื่อระบุการแยกอาร์เรย์ที่เป็นไปได้ทั้งหมด

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.