靴下の整理を手伝ってください!


30

ペアに分類したいきれいな靴下が山ほどあります。残念ながら、靴下は中央ではなく、パイルの両端からしか取れません。さらに、一致するペアを一度に山から靴下のみを削除できます。私の戦略は、最初にパイルを1つ以上の小さなパイルに分割することです。いくつかの例でこれが明らかになると思います。各靴下を正の整数として表します(整数が一致する場合は、靴下が等しいことを示します)。

靴下の最初の山が

1 2 3 3 2 1

その後、分割する必要はありません。両方の1靴下、次に両方の2靴下、次に両方の3靴下を取り外します。

代わりに、初期パイルが

1 2 3 2 3 1

靴下を端から取り外すだけではすべての靴下をペアリングできないため、最初に分割する必要があります。1つの可能性は、それを2つの山に分割することです

1 2 3 and 2 3 1

今、私は削除することができ1、靴下を残し2 3 and 2 3、続い3靴下、残して2 and 2、そして最後に2靴下。

あなたの仕事

靴下の最初の山を考えて、靴下を並べ替えることができるように小さな山に分割するプログラムを作成します。プログラムは、パイルを可能な限り少ない数のパイルに分割する必要があります(最適なソリューションが複数ある場合は、1つだけ見つける必要があります)。

入力は、リスト、区切り文字列、またはその他の便利な形式で提供されます。間1にある整数と最大値の間の整数のみが含まれn、各整数は正確に2回発生します。

出力は、任意の便利な形式で与えられた、より小さなリストに分割された入力リストで構成される必要があります。

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

これらの入力のほとんどで許可される出力はこれだけではないことに注意してください。たとえば、2番目の場合、出力1 2; 1 2または1 2 1; 2は受け入れられます。

テストの提案をしてくれたSp3000に感謝します!

服を並べ替えるのに長い時間をかけるのは嫌いなので、コードはできるだけ短くしてください。バイト単位の最短回答が勝ちます!

ノート

  • 靴下の後ろを見て、一致するペアが存在するかどうかを確認する必要はありません。そのため、ペアで両方のソックスを同じ端から持ち出すことは許可されていません。例えば、パイルが1 1 2 2その場合、1つのパイル1のままにして、左端から両方の靴下を取ることはできません。

5
PPCG Carmeisterへようこそ。これは非常に良い最初のチャレンジ+1です。
ロジックナイト

1
PPCGへようこそ!これは非常に良い最初の質問です。この質問には大きな問題はないようですが、投稿する前に、ユーザーがSandboxを使用して課題に関するフィードバックを受け取ることをお勧めします。
メゴ

だから、123213に分割することができ1; 23; 2131; 23; 213- > 1; 2; 21- > ; 2; 2)?
R.ガプス

@Megoありがとう!今後もそうするつもりです。@ R.Kapそれはそれを分割する有効な方法ですが、答えは、それを可能な限り最小数のパイルに分割する分割を与えるべきです。1232132つのパイルのみを使用して分割することが可能であるため、答えは2パイルの分割のいずれかを与える必要があります。
カーマイスター16

1
@ven私はあなたの質問を完全に理解しているわけではありませんが、手に入れることができる靴下は、各パイルの始まりと各パイルの終わりのものです。
カーマイスター16

回答:


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>

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.