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>