Anda di halaman 1dari 10

Implementasi Algoritma Divide and Conquer Untuk Penyelesaian 2009

Masalah Convex Hull

Implementasi Algoritma Divide and Conquer


Untuk Penyelesaian Masalah Convex Hull
Boy Dewa Priambada

Program Pascasarjana Ilmu Komputer


Institut Pertanian Bogor

Abstrak - Tulisan ini memberikan gambaran tentang implementasi algoritma divide and
conquer untuk penyelesaian masalah convex hull. Dengan algoritma divide and conquer
masalah convex hull dapat diselesaikan dengan kompleksitas yang cukup rendah yaitu
sebesar O(n log n).

Pendahuluan
Segala bentuk dan wujud yang ada di sekitar manusia didefinisikan ke dalam geometri.
Permasalahan geometri komputasional biasanya melingkupi objek-objek geometri seperti
himpunan titik, himpunan garis, himpunan segmen, dan juga poligon. Permasalahan yang
berkaitan dengan penentuan bentuk geometri dapat diselesaikan dengan menggunakan
algoritma pencarian convex hull.
Usaha pencarian algoritma yang efisien untuk pencarian convex hull sudah dilakukan
sejak lama dan masih dilakukan sampai sekarang. Satu dari berbagai algoritma yang dapat
dimanfaatkan dalam pencarian convex hull adalah divide and conquer. Divide and Conquer
adalah metode pemecahan masalah yang bekerja dengan membagi masalah menjadi beberapa
submasalah yang lebih kecil, kemudian menyelesaikan masing-masing submasalah tersebut
secara independen, dan akhirnya menggabungkan solusi masing-masing submasalah sehingga
menjadi solusi dari masalah semula (Noorzaman, 2007). Tulisan ini memberikan gambaran
tentang implementasi algoritma divide and conquer untuk penyelesaian masalah convex hull.

Convex Hull
Menurut Novandi (2007), sebuah subset S dari bidang R disebut konveks jika dan
hanya jika pada seluruh dua buah titik sembarang p, q є S dibentuk garis yang seluruhnya
berada dalam S[1].

Gambar 1. Convex set

Pencarian convex hull dari sebuah himpunan titik Q (CH(Q)) adalah mencari sebuah
convex set terkecil yang memuat seluruh titik pada Q. Convex hull dari dari sebuah himpunan
titik Q (CH(Q)) pada n dimensi adalah seluruh irisan dari semua convex set yang

0|Page
Implementasi Algoritma Divide and Conquer Untuk Penyelesaian 2009
Masalah Convex Hull

mengandung Q. Lebih lanjut, untuk N buah titik p1, p2, ... pN. convex hull merupakan
himpunan convex combination yang dinyatakan dengan:

Definisi lain dari convex hull adalah poligon yang disusun dari subset titik sedemikian
sehingga tidak ada titik dari himpunan awal yang berada di luar poligon tersebut (semua titik
berada di batas luar atau di dalam area yang dilingkupi oleh poligon tersebut).
Petunjuk untuk menyelesaikan persoalan ini adalah persamaan garis pada bidang.
Persamaan garis pada bidang memisahkan bidang menjadi dua bagian yaitu area di sebelah
kanan bidang (relatif terhadap orientasi garis). Sebagai contoh garis berorientasi adalah
sumbu koordinat. Misalkan saja sumbu vertikal (ordinat, arah orientasi ke atas), seluruh titik
di sebelah kanan garis ini memiliki nilai komponen koordinat horizontal (X) yang positif
sedangkan seluruh titik di sebelah kiri garis memiliki nilai komponen koordinat horizontal
negatif.
Petunjuk di atas dimanfaatkan dengan membuat definisi bahwa garis yang dibentuk
oleh titik-titik poligon jika diasumsikan memiliki orientasi yang sama, maka setiap titik
berada di sebelah kanan seluruh garis batas tersebut. Definisi ini kemudian dimanfaatkan
untuk menentukan aksi awal yaitu memilih titik yang berada paling luar pertama. Mencari
titik pertama cukup mudah yaitu cukup memilih titik yang memiliki nilai komponen
koordinat (horizontal atau vertikal) yang ekstrim (minimum atau maksimum). Titik-titik
convex hull lainnya ditentukan berdasarkan titik pertama tadi.

Gambar 2. Inisiasi permasalahan dari Convex Hull

Banyak sekali algoritma yang dapat digunakan untuk menyelesaikan permasalahan


convex hull dengan kompleksitas yang berbeda-beda, misalnya saja dengan pendekatan brute
force didapat kompleksitas sebesar O(n4), gift wrapping dengan kompleksitas sebesar O(nh),
incremental methods dengan kompleksitas sebesar O(n log n), sweeping dengan kompleksitas
sebesar O(n log n), divide-and-conquer dengan kompleksitas sebesar O(n log n), Monotone
Chain dengan kompleksitas sebesar O(n log n) ( J. O'Rourke, 1998).
Grafika komputer, otomasi desain, pengenalan pola (pattern recognition), dan
penelitian operasi merupakan contoh aplikasi terapan yang menggunakan permasalahan
convex hull untuk mencari suatu solusi yang dapat diolah menggunakan aplikasi komputer
(Noorzaman, 2007).

Algoritma Divide and Conquer

1|Page
Implementasi Algoritma Divide and Conquer Untuk Penyelesaian 2009
Masalah Convex Hull

Algoritma divide and conquer adalah metode pemecahan masalah dengan membagi
masalah ke menjadi submasalah yang lebih kecil, memecahkan setiap submasalah secara
rekursif dan menggabungkan hasil yang sesuai untuk sebuah solusi lengkap.
Pada algoritma divide and conquer ini memiliki tiga proses utama yaitu:
- Divide: membagi masalah menjadi beberapa submasalah yang memiliki kemiripan
dengan masalah semula namun berukuran lebih kecil (idealnya berukuran hampir sama),
- Conquer: memecahkan (menyelesaikan) masing-masing submasalah (secara rekursif),
dan
- Combine: mengabungkan solusi masing-masing submasalah sehingga membentuk solusi
masalah semula.
Objek masalah yang dibagi adalah masukan (input) atau instances yang berukuran n:
tabel, matriks, dan sebagainya, bergantung pada masalahnya. Tiap-tiap submasalah
mempunyai karakteristik yang sama dengan karakteristik masalah semula, sehingga metode
divide and conquer lebih natural diungkapkan dalam skema rekursif. Sesuai dengan
karakteristik pembagian dan pemecahan masalah tersebut, maka algoritma ini dapat berjalan
baik pada persoalan yang bertipe rekursif (perulangan dengan memanggil dirinya sendiri).
Dengan demikian, algoritma ini dapat diimplementasikan dengan cara iteratif (perulangan
biasa), karena pada prinsipnya iteratif hampir sama dengan rekursif.
Penggunaan secara spesifik algoritma ini adalah untuk mencari nilai minimal dan
maksimal serta untuk mengurutkan elemen array. Dalam hal pengurutan ini ada empat
macam algoritma pengurutan yang berdasar pada algoritma divide and conquer, yaitu merge
sort, insert sort, quick sort, dan selection sort. Merge sort dan quick sort mempunyai
kompleksitas algoritma O(n log n). Hal ini lebih baik jika dibandingkan dengan pengurutan
biasa dengan menggunakan algoritma brute force. Secara umum, algoritma divide and
conquer memiliki skema sebagai berikut:
procedure DIVIDE_and_CONQUER(input n : integer)
{ Menyelesaikan masalah dengan algoritma divide and conquer
Masukan: masukan yang berukuran n
Keluaran: solusi dari masalah semula
}
Deklarasi
r, k : integer
Algoritma
if n ≤ n0 then {ukuran masalah sudah cukup kecil }
SOLVE submasalah yang berukuran n ini
else
Bagi menjadi r submasalah, masingmasing berukuran n/k
for masing-masing dari r submasalah do
DIVIDE_and_CONQUER(n/k)
endfor
COMBINE solusi dari r submasalah menjadi solusi masalah semula
endif

Pemecahan Masalah Convex Hull dengan Algoritma Divide and Conquer


Pada penyelesaian masalah pencarian Convex Hull dengan menggunakan algoritma
Divide and Conquer, hal ini dapat dipandang sebagai generalisasi dari algoritma pengurutan
merge sort. Berikut ini merupakan garis besar gambaran dari algoritmanya:

2|Page
Implementasi Algoritma Divide and Conquer Untuk Penyelesaian 2009
Masalah Convex Hull

- Lakukan pengurutan p1, p2, ... pN dalam koordinat X |S|


- Buat partisi himpunan titik-titik tersebut menjadi 2 himpunan A dan B, dimana A terdiri
dari setengah jumlah dari |S| dan titik dengan koordinat X yang terendah dan B terdiri dari
setengah dari jumlah |S| dan titik dengan koordinat X terbesar
- Secara rekursif lakukan penghitungan terhadap HA = conv(A) dan HB = conv(B)
- Gabungkan (merge) kedua hull tersebut menjadi convex hull, H, dengan menghitung dan
mencari upper dan lower hull (tangents) untuk HA dan HB. Setiap titik searah jarum jam
untuk himpunan yang berada di sebelah kanan, dan berlawanan arah jarum jam pada
himpunan yang berada di sebelah kiri. dengan mengabaikan semua titik yang berada
diantara dua buah tangen ini

Gambar 3. Divide And Conquer.

Gambar 4. Menggabungkan 2 buah upper hull.

Untuk mencari upper hull dan lower hull dapat digunakan algoritma sebagai berikut:
Algorithm UpperHull(P)
if |P| 2 then return the obvious answer
else begin
Compute the median xmed of x-coordinates of points in P.

3|Page
Implementasi Algoritma Divide and Conquer Untuk Penyelesaian 2009
Masalah Convex Hull

Partition P into two sets L and R each of size about n/2 around the median xmed .
Find the upper bridge pq of L and R, p L, and q R
L { r L x(r) x(p) }
R { r R x(r) x(q) }
LUH UpperHull(L )
RUH UpperHull(R )
return the concatenated list LUH, pq, RUH as the upper hull of P.
end

Waktu yang diperlukan untuk menjalankan algoritma tersebut dapat dijelaskan dengan relasi
rekursi sebagai berikut:

Algoritma tersebut menghasilkan kompleksitas waktu sebesar O(n log n).

Kesimpulan
Grafika komputer, otomasi desain, pengenalan pola (pattern recognition), dan
penelitian operasi merupakan contoh aplikasi terapan yang menggunakan permasalahan
convex hull untuk mencari suatu solusi yang dapat diolah menggunakan aplikasi komputer.
Algoritma divide and conquer adalah metode pemecahan masalah dengan membagi
masalah ke menjadi submasalah yang lebih kecil, memecahkan setiap submasalah secara
rekursif dan menggabungkan hasil yang sesuai untuk sebuah solusi lengkap. Algoritma divide
and conquer merupakan salah satu algoritma yang dapat memecahkan masalah convex hull
dengan kompleksitas yang cukup rendah yaitu sebesar O(n log n).

Daftar Pustaka
http://pagesperso-orange.fr/colin.barker/lpa/div_conq.htm Diakses pada tanggal 23
Nopember 2009 Pukul 23.00.
http://www.cse.unsw.edu.au/ Diakses pada tanggal 17 Nopember 2009 Pukul 12.00.
J. O'Rourke. Computational Geometry in C (2nd ed.). Cambridge University Press, 1998
M. C. Timothy. A Minimalist's Implementation of the 3-d Divide-and-Conquer Convex Hull
Algorithm. School of Computer Science, University of Waterloo, Canada. 2003.
N. Stefan and Daniel Schmitt. A Framework for Multi-Core Implementations of Divide and
Conquer Algorithms and its Application to the Convex Hull Problem. Department of
Computer Science, University of Trier, Germany. 2008.
Noorzaman Geri. Analisis dan Penerapan Algoritma Divide and Conquer Dalam
Penyelesaian Masalah Convex Hulls. Jurusan Informatika, Sekolah Teknik Elektro dan
Informatika Institut Teknologi Bandung. 2007.
Novandi Petra. Analisis Kompleksitas Algoritma Pencarian Convex Hull Pada Bidang Planar.
Program Studi Teknik Informatika, Institut Teknologi Bandung. 2007.

4|Page
Implementasi Algoritma Divide and Conquer Untuk Penyelesaian 2009
Masalah Convex Hull

Lampiran

This algorithm is due to Preparata and Hong.

/*
* Convex Hull
* The convex hull of a set of points is the smallest convex region
* containing the points
*/

/* divide_and_conquer(Points, ConvexHullVertices) is true if Points is a


*/
/* list of points in the form p(X,Y), and ConvexHullVertices are the
*/
/* vertices in the form p(X,Y) of the convex hull of the Points, in
*/
/* clockwise order, starting and ending at the smallest point (as
*/
/* determined by X-values, and by Y-values to resolve ties). No three
*/
/* vertices of the convex hull will be collinear.
*/
/*
e.g.divide_and_conquer([p(0,6),p(3,7),p(4,6),p(4,5),p(3,4),p(2,4),p(5,0)],*
/
/* [p(0,6),p(3,7),p(4,6),p(5,0),p(0,6)]).
*/
divide_and_conquer(Ps, Qs):-
sort(Ps, Ps1), % Duplicated points are discarded
length(Ps1, N),
divide_and_conquer_1(N, Ps1, Qs, []).

divide_and_conquer_1(1, [X|Ps], [X,X], Ps):-!.


divide_and_conquer_1(2, [X,Y|Ps], [X,Y,X], Ps):-!.
divide_and_conquer_1(3, [X,Y,Z|Ps], [X,Y,Z,X], Ps):-
strictly_to_right(Z, X, Y), !.
divide_and_conquer_1(3, [X,Y,Z|Ps], [X,Z,Y,X], Ps):-
strictly_to_left(Z, X, Y), !.
divide_and_conquer_1(3, [X,_,Z|Ps], [X,Z,X], Ps):-!.
divide_and_conquer_1(N, Ps, Qs, Rs):-
N1 is N // 2,
N2 is N - N1,
divide_and_conquer_1(N1, Ps, Left, Temp),
divide_and_conquer_1(N2, Temp, Right, Rs),
union(Left, Right, Qs).

/* length(Xs, L) is true if L is the number of elements in the list Xs.


*/
%length(Xs, L):-length_1(Xs, 0, L).

/* length_1(Xs, L0, L) is true if L is equal to L0 plus the number of


*/
/* elements in the list Xs.
*/
%length_1([_|Xs], L0, L):-L1 is L0 + 1, length_1(Xs, L1, L).
%length_1([], L, L).

/* strictly_to_left(Pa, Pb, Pc) is true if Pa is strictly to the left of


the */

5|Page
Implementasi Algoritma Divide and Conquer Untuk Penyelesaian 2009
Masalah Convex Hull

/* directed line from Pb to Pc.


*/
strictly_to_left(p(Xa,Ya), p(Xb,Yb), p(Xc,Yc)):-
(Xb-Xa) * (Yc-Ya) - (Xc-Xa) * (Yb-Ya) > 0.0.

/* strictly_to_right(Pa, Pb, Pc) is true if Pa is strictly to the right of


*/
/* the directed line from Pb to Pc.
*/
strictly_to_right(p(Xa,Ya), p(Xb,Yb), p(Xc,Yc)):-
(Xb-Xa) * (Yc-Ya) - (Xc-Xa) * (Yb-Ya) < 0.0.

/* are_collinear(Pa, Pb, Pc) is true if Pa, Pb and Pc are collinear.


*/
are_collinear(p(Xa,Ya), p(Xb,Yb), p(Xc,Yc)):-
(Xb-Xa) * (Yc-Ya) - (Xc-Xa) * (Yb-Ya) =:= 0.0.

/* is_nearer(Pa, Pb, Pc) is true if the distance from Pa to Pc is strictly


*/
/* less than the distance from Pb to Pc.
*/
is_nearer(p(Xa,Ya), p(Xb,Yb), p(Xc,Yc)):-
Xa_Xc is Xa - Xc,
Ya_Yc is Ya - Yc,
Xb_Xc is Xb - Xc,
Yb_Yc is Yb - Yc,
(Xa_Xc)*(Xa_Xc) + (Ya_Yc)*(Ya_Yc) < (Xb_Xc)*(Xb_Xc) + (Yb_Yc)*(Yb_Yc).

/*
* Union of disjoint convex hulls
*/

/* Given P1, find Q2, the first point in Qs s.t. P1-Q2 is a tangent for Qs.
*/
/* If P2 is strictly to the right of P1-Q2, return P1-Q2.
*/
/* Given Q2, find P2, the first point in Ps s.t. P2-Q2 is a tangent for Ps.
*/
/* If Q3 is strictly to the right of P2-Q2, return P2-Q2.
*/

/* union(Ps, Qs, Rs) is true if Ps and Qs are disjoint convex hulls, all
*/
/* vertices of Ps being to the left of all the vertices of Qs, and Rs is
*/
/* the convex hull of the union of the vertices of Ps and Qs. For each
*/
/* convex hull, the vertices are in the form p(X,Y), in clockwise order,
*/
/* starting and ending at the smallest point (as determined by X-values,
*/
/* and by Y-values to resolve ties), and no three vertices are collinear.
*/
/* This is a O(n) time algorithm.
*/
/* This may not work for some degenerate convex hulls, but should work in
*/
/* all cases when called by divide_and_conquer_1/4.
*/

6|Page
Implementasi Algoritma Divide and Conquer Untuk Penyelesaian 2009
Masalah Convex Hull

/* e.g. union([p(0,1),p(1,3),p(2,3),p(3,0),p(0,1)],
*/
/* [p(4,0),p(4,1),p(5,2),p(7,2),p(4,0)],
*/
/* [p(0,1),p(1,3),p(2,3),p(7,2),p(4,0),p(3,0),p(0,1)]).
*/
union(Ps, Qs, Rs):-
split_left_hull(Ps, [], Ps1, Ps2),
split_right_hull(Qs, Qs2),
bridge(Ps1, Qs, A, B, Qs3),
bridge(Qs2, Ps2, C, D, Ps3),
concatenate([B|Qs3], C, [D|Ps3], Rs0),
concatenate(Ps, A, Rs0, Rs).

/* split_left_hull(Ps, [], Xs, Ys) is true if Xs is the reverse of the


*/
/* points in Ps up to and including the rightmost point, and Ys are the
*/
/* remaining points in Ps starting at the rightmost point.
*/
/* e.g. split_left_hull([p(0,1),p(1,3),p(2,3),p(3,0),p(0,1)], [],
*/
/* [p(3,0),p(2,3),p(1,3),p(0,1)], [p(3,0),p(0,1)]).
*/
split_left_hull(Ps, Xs, [P1|Xs], Ps):- % For a one-point hull
Ps=[P1,P2|_],
P1=P2, !.
split_left_hull(Ps, Xs, [P1|Xs], Ps):-
Ps=[P1,P2|_],
lt(P2, P1), !.
split_left_hull([P1|Ps], Xs0, Xs, Ys):-
split_left_hull(Ps, [P1|Xs0], Xs, Ys).

/* split_right_hull(Qs, Ys) is true if Ys is the reverse of the points in


Qs */
/* starting at the rightmost point.
*/
/* e.g. split_right_hull([p(4,0),p(4,1),p(5,2),p(7,2),p(4,0)],
*/
/* [p(4,0),p(7,2)]).
*/
split_right_hull(Qs, Ys):- % This clause is probably redundant
Qs=[Q1,Q2|_],
Q2=Q1, !,
reverse(Qs, Ys).
split_right_hull(Qs, Ys):-
Qs=[Q1,Q2|_],
lt(Q2, Q1), !,
reverse(Qs, Ys).
split_right_hull([_|Qs], Ys):-
split_right_hull(Qs, Ys).

lt(p(X,_), p(X1,_)):-X < X1, !.


lt(p(X,Y), p(X,Y1)):-Y < Y1.

/* bridge(Ps, Qs, P, Q, Qs1) is true if Ps are the vertices of the left


*/
/* convex hull starting at the rightmost point going anti-clockwise to
the */

7|Page
Implementasi Algoritma Divide and Conquer Untuk Penyelesaian 2009
Masalah Convex Hull

/* leftmost point, Qs are the vertices of the right convex hull starting
*/
/* and ending at the leftmost point going clockwise, the line from P (a
*/
/* point in Ps) to Q (a point in Qs) is a left tangent for the convex
*/
/* hulls, and Qs1 are the points following Q in Qs.
*/
/* e.g. bridge([p(3,0),p(2,3),p(1,3),p(0,1)],
*/
/* [p(4,0),p(4,1),p(5,2),p(7,2),p(4,0)],
*/
/* p(2,3), p(7,2), [p(4,0)]).
*/
bridge(Ps, Qs, P, Q, Qs1):-
Ps=[P1|_],
tangent_to_right_hull(Qs, P1, Qs0),
bridge_1(Ps, Qs0, P, Q, Qs1).

bridge_1([P], [Q|Qs], P, Q, Qs):-!.


bridge_1([P,P1|_], [Q|Qs], P, Q, Qs):-
strictly_to_right(P1, P, Q), !.
bridge_1([_|Ps], Qs, P, Q, Qs1):-
Qs=[Q1|_],
tangent_to_left_hull(Ps, Q1, Ps1),
bridge_2(Qs, Ps1, P, Q, Qs1).

bridge_2([Q], [P|_], P, Q, []):-!.


bridge_2([Q,Q1|Qs], [P|_], P, Q, [Q1|Qs]):-
strictly_to_right(Q1, P, Q), !.
bridge_2([Q,Q1|Qs], [P|_], P, Q, [Q1|Qs]):- % For some 2-vertex Qs
are_collinear(P, Q, Q1),
is_nearer(Q1, Q, P), !.
bridge_2([_|Qs], Ps, P, Q, Qs1):-
Ps=[P1|_],
tangent_to_right_hull(Qs, P1, Qs2),
bridge_1(Ps, Qs2, P, Q, Qs1).

/* tangent_to_right_hull(Qs, P, Qs1) is true if the head of Qs1 is the last


*/
/* element (and the tail of Qs1 are the remaining elements) of Qs (a
*/
/* convex chain going clockwise) such that the line from P to Q is a
*/
/* tangent for Qs.
*/
/* e.g. tangent_to_right_hull([p(4,0),p(4,1),p(5,2),p(7,2),p(4,0)], p(3,0),
*/
/* [p(5,2),p(7,2),p(4,0)]).
*/
tangent_to_right_hull([Q], _, [Q]):-!.
tangent_to_right_hull(Qs, P, Qs):-
Qs=[Q,Q1|_],
strictly_to_right(Q1, P, Q), !.
tangent_to_right_hull(Qs, P, Qs):- % For some 2-vertex Qs
Qs=[Q,Q1|_],
are_collinear(P, Q, Q1),
is_nearer(Q1, Q, P), !.
tangent_to_right_hull([_|Qs], P, Qs1):-
tangent_to_right_hull(Qs, P, Qs1).

8|Page
Implementasi Algoritma Divide and Conquer Untuk Penyelesaian 2009
Masalah Convex Hull

/* tangent_to_left_hull(Ps, Q, Ps1) is true if the head of Ps1 is the first


*/
/* element (and the tail of Ps1 are the remaining elements) of Ps (a
*/
/* convex chain going anti-clockwise) such that the line from Q to P is a
*/
/* tangent for Ps.
*/
/* e.g. tangent_to_left_hull([p(3,0),p(2,3),p(1,3),p(0,1)], p(5,2),
*/
/* [p(2,3),p(1,3),p(0,1)]).
*/
tangent_to_left_hull([P], _, [P]):-!.
tangent_to_left_hull(Ps, Q, Ps):-
Ps=[P,P1|_],
strictly_to_right(P1, P, Q), !.
tangent_to_left_hull([_|Ps], Q, Ps1):-
tangent_to_left_hull(Ps, Q, Ps1).

/* concatenate(Ps, P, Qs0, Qs) is true if the list Qs consists of the


*/
/* elements of Ps up to and including the element P, followed by the
*/
/* elements of Qs0.
*/
/* e.g. The goal
*/
/* concatenate([9,10,11,12,13], 11, [], Y),
*/
/* concatenate([5,6,7,8,9], 7, [-8|Y], Z),
*/
/* concatenate([1,2,3,4,5], 3, [-4|Z], A).
*/
/* gives Y=[9,10,11] Z=[5,6,7,-8,9,10,11] A=[1,2,3,-4,5,6,7,-8,9,10,11]
*/
concatenate([P|_], P, Qs, [P|Qs]):-!.
concatenate([Q|Ps], P, Qs0, [Q|Qs]):-
concatenate(Ps, P, Qs0, Qs).

/* reverse(Xs, Ys) is true if Ys is the result of reversing the order of


*/
/* the elements in the list Xs.
*/
%reverse(Xs, Ys):-reverse_1(Xs, [], Ys).

%reverse_1([], As, As).


%reverse_1([X|Xs], As, Ys):-reverse_1(Xs, [X|As], Ys).

9|Page