帮我整理袜子!


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 21 2 1; 2也将被接受。

感谢Sp3000提供一些测试建议!

我讨厌花很长时间整理衣服,所以要使代码尽可能短。以字节为单位的最短答案胜出!

笔记

  • 我不想在袜子后面看一看是否有匹配的袜子,所以不允许从同一端将两只袜子都放在袜子里。例如,如果那是一堆,1 1 2 2那么您将无法将其作为一堆,1从左端拿起两只袜子。

5
我可以欢迎您来到PPCG Carmeister。这是一个很好的第一个挑战+1。
逻辑骑士

1
欢迎来到PPCG!这是一个很好的第一个问题。尽管此问题似乎没有什么大问题,但我们鼓励用户使用沙盒在发布挑战之前收到有关其挑战的反馈。
Mego

那么123213可以分为1; 23; 2131; 23; 213-> 1; 2; 21-> ; 2; 2)吗?
R. Kap

@Mego谢谢!我一定会在将来这样做。@ R.Kap这是将其拆分的有效方法,但答案应该是将其拆分为尽可能少的桩数的拆分。由于可以123213仅使用两个桩进行拆分,因此您的答案将必须是两桩拆分中的一个。
Carmeister '16

1
@ven我不确定我是否完全理解您的问题,但是可以拿的袜子是每堆开始时的袜子和每堆结束时的袜子。
Carmeister '16

Answers:


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>

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.