양말을 도와주세요!


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에 오신 것을 환영합니다! 이것은 매우 좋은 첫 번째 질문입니다. 이 질문에 큰 문제는없는 것으로 보이지만 사용자는 샌드 박스 를 사용하여 문제를 게시하기 전에 해당 문제에 대한 피드백을받는 것이 좋습니다 .
Mego

그래서 ( -> -> ) 123213로 나눌 수 있습니까? 1; 23; 2131; 23; 2131; 2; 21; 2; 2
R. Kap

@ 메고 감사합니다! 앞으로도 그렇게 할 것입니다. @ R.Kap 그것은 그것을 나누는 유효한 방법 일 것이지만, 대답은 그것을 가능한 가장 적은 수의 더미로 나누는 나누기를 제공해야합니다. 123213두 개의 파일 만 사용하여 분할 할 수 있기 때문에 답은 2 파일 분할 중 하나를 제공해야합니다.
Carmeister

1
@ven 나는 당신의 질문을 완전히 확신하지 못하지만 취할 수있는 양말은 각 더미의 시작 부분과 끝에있는 양말입니다.
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

자바 스크립트 (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>

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.