JavaScript (ES6), 329
Birleştirici yerleşik olmayan bir dil için kolay bir iş değil.
Muhtemelen daha yumuşak bir şekilde golf oynamak mümkün.
Not: Tüm bölümler en az 2 boyuttadır, çünkü tek elemanlı bölümler her zaman daha az faydalıdır.
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}
Parça açıklaması
(Aşırı derecede ayrıntılı, ama açıklamak zor buldum - sonunda "hepsini bir araya koymak" için atlayın)
Bir dizinin tüm olası bölümlerini numaralandırmak için bir özyinelemeli işlev
// 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"]]
Şimdi, 2 veya daha büyük boyutta bölümlere ihtiyacım var, bu yüzden bu işlevi kaydırmalı olarak farklı parametrelerle kullanmalıyım. V parametresi "dizi boyutu - istenen bölüm sayısı - 1" dir. O zaman bölümleri biraz farklı bir şekilde oluşturmalıyım.
// 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"]]
Böylece, hiçbir bölünme, 1 bölme, 2 bölme vb. İçin bölümlerin listesini numaralandırabilirim. Çalışan bir bölüm bulduğumda, sonuçta duracağım ve çıktısını alacağım.
Kontrol etmek için, bölüm listesini tarayın, eğer her birinin başında ve sonunda bulunan değerleri not alın. Sonunda hiçbir şey çıkarılana kadar tekrarlayın: eğer tüm çiftler çıkarılmışsa bu bölüm iyidir.
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)
Ardından, eksik olan kısım, G sayısını bölümleme sayısını arttıran G işlevini calop eden bir döngüdür. Bir sonuç bulunduğunda döngüden çıkar.
Hepsini bir araya getirmek
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
}
Ölçek
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>