Bài toán xếp lịch
Bài toán xếp lịch 18 Tháng Ba 201111:48 SA Ứng dụng thuật toán tô màu đồ thị để giải quyết Bài toán xếp lịch Giới thiệu bài toán Bài toán xếp lịch có một lịch sử phát triển dài, trải qua nhiều sự thay đổi lớn. Kể từ những thế hệ đầu tiên của máy tính,người ta đã nghĩ đến việc sử dụng máy tính để trợ giúp người xếp lịch. Ban đầu đó chỉ là những công cụ trợ giúp cho việc phân công những công việc điều hành phối hợp. Sau này mới thực sự được phát triển thành những công cụ xếp lịch cụ thể. Bài toán xếp lịch được chia thành những lớp bài toán cụ thể sau: - Xếp thời khoá biểu. Thường được sử dụng trong các trường Phổ thông, Đại học.- Xếp lịch thi. Được quan tâm mỗi khi kì thi tuyển sinh Đại học hoặc thi học kì ở các trường Đại học và Cao đẳng.- Xếp lịch công tác cán bộ. Được sử dụng chủ yếu ở các cơ quan, tổ chức lớn . Tuy nhiên trong bài báo này chúng ta chỉ quan tâm đến bài toán xếp lịch thi trong các trường Đại học. Phát biểu bài toán Bài toán được phát biểu như sau: Vào cuối mỗi một học kì, các trường đại học phải tổ chức một đợt thi cho từng khoa hoặc cả trường. Trường có một nhiều phòng thi, các phòng có kích cỡ khác nhau (khả năng chứa thí sinh). Mỗi lớp có thể được chia thành nhiều nhóm thi, mỗi nhóm thi thi trong một phòng, mỗi phòng có thể có nhiều nhóm cùng thi. Và tổng số lượng thí sinh của các nhóm phải nhỏ hơn hoặc bằng kích cỡ của phòng. Kì thi được chia thành các đợt thi. Mỗi nhóm sẽ thi một môn trong một đợt thi. Yêu cầu chặt chẽ: có một số môn thi không được thi cùng đợt với môn thi khác, các nhóm của cùng một lớp (nếu có thể) phải thi trong cùng một đợt. Ta có thể chia bài toán trên thành 2 bài toán đơn giản hơn: - Phân bổ các nhóm thi vào các đợt thi sao cho chúng không xung đột nhau (không vi phạm ràng buộc). Xây dựng một đồ thị G, với mỗi đỉnh là một nhóm, nối cạnh giữa hai đỉnh mà nhóm của chúng có ràng buộc với nhau, tìm cách tô màu và sắc số p của đồ thị G. Số p là giới hạn dưới của số các đợt thi. Các đỉnh được tô cùng màu có nhóm tương ứng được xếp vào một đợt thi. - Tìm cách xếp các nhóm trong một đợt thi (đã tìm được ở trên) vào các phòng thi của trường. Bài toán tô màu đồ thị và sắc số đồ thị Cho trước một số nguyên dương P, ta nói rằng đồ thị G có P sắc có nghĩa là: chỉ bằng P màu khác nhau ta có thể tô màu tất cả các đỉnh sao cho 2 đỉnh liền kề bất kỳ có màu khác nhau. Khi số p nhỏ nhất thì ta gọi P là sắc số của đồ thị và việc tìm cách tô P màu lên đồ thị chính là bài toán tô màu đồ thị. Ví dụ: Việc tô màu bản đồ hành chính, ta phải tô màu các nước sao cho: mỗi Quốc gia được tô một màu, hai nước có liền kề (có chung biên giới) không được tô cùng một màu. Ta thiết lập một đồ thị G, có tập các đỉnh là tập tất cả các quốc gia trên bản đồ. Hai nước liền kề nhau thì có cạnh nối hai đỉnh tương ứng với nhau. Ta tiến hành tìm sắc số của đồ thị này. Đây là trường hợp riêng của bài toán tô màu đồ thị. Khi đồ thị chỉ là đồ thị phẳng. Người ta đã chứng minh được rằng: chỉ cần nhiều nhất là 4 màu để tô đồ thị này. Từ lâu người ta đã chứng minh bài toán tô màu đồ thị thuộc lớp NP - đầy đủ. Tuy nhiên nếu dùng một chiến thuật thuật hợp lý thì kết quả thu được cũng có thể chấp nhận được. Thuật toán tìm sắc số của đồ thị (Thuật toán 1): Giả sử chúng ta có một đồ thị chứa các đỉnh x và y. G: xy là một đồ thị thu được từ đồ thị G bằng cách thay thế hai đỉnh x và y bằng một đỉnh, đỉnh đó có cạnh nối tới tất cả các đỉnh kề với đỉnh x, yhoặc cả x lẫn y. Hay là hai đỉnh x và y đã được nhập với nhau. Đồ thị G - {x} là một đồ thị thu được từ đồ thị G bằng cách loại bỏ đỉnh x cùng với tất cả các cạnh nối tới đỉnh x đó. Một đồ thị trống là đồ thị không chứa một đỉnh hay một cạnh nào. Hai đỉnh gọi là kề nhau nếu có cạnh nối với nhau. Với một đỉnh x bất kỳ, ta xây dựng một tập các bộ 3 như sau:Graph Code:L ựa chọn code | Ẩ n/Hi ệ n code (x, z(1,1), y1) (x, z(1,2), y1) . (x, z(1,m1), y1) . (x, z(i,1), yi) (x, z(i,2), yi) . (x, z(i,mi), yi) . . (x, z(n,mn), yn)Trong đó đỉnh thứ nhất kề với đỉnh thứ hai, đỉnh thứ 2 kề với đỉnh thứ 3. Và không tồn tại một bộ 3 nào mà: đỉnh thứ nhất kề hoặc trùng với đỉnh thứ 3. Từ tập các bộ 3 đó, ta tìm các đỉnh yi sao cho có: mi = max(m1, m2, ., mn) và đặt yi = x. Nếu có nhiều đỉnh y đạt max ta chọn đỉnh đầu tiên. Ta có thể hình dung: Chọn một đỉnh trong số những đỉnh không kề với đỉnh x, kề với đỉnh (đỉnh trung gian) kề với đỉnh x, có số đỉnh trung gian là lớn nhất. Các bước của thuật toán (đồ thị G là dữ liệu vào): Bước 1: Đặt j = 1, H=G. Bước 2: Đặt vj là đỉnh có bậc cao nhất trong H. Bước 3: Từ vj xây dựng tất cả các bộ 3 như trên và tìm đỉnh x. Nếu không tìm được x, trong trường hợpkhông tìm được bộ 3 nào, chọn một đỉnh có bậc lớn nhất không kề với vj. Bước 4: Nhập x vào vj và quay lại bước 3 cho tới khi không chọn được một đỉnh nào nữa thì quay lại bước 2 với : H=H-{vj}, j=j+1. Bước 5: Khi không còn một đỉnh nào còn lại trong H, dựng lại và tô màu i cho tất cả các đỉnh được nhập vào vi với (1 =< i =< j). Khi đó j là sắc số của đồ thị G. Cài đặt: Dữ liệu: Mảng hai chiều M chứa ma trận thể hiện đồ thị n đỉnh. Mảng 1 chiều n phần tử: Color đánh dấu màu của đỉnh i là Color[i]. Mảng 1 chiều n phần tử: Merged, Merged[i]=true nếu đỉnh i đã bị nhập vào 1 đỉnh khác. Sắc số của đồ thị: Cromatic. Một số thủ tục và hàm sử dụng trong chương trình: Procedure Input; Nhập ma trận thể hiện đồ thị G từ file. Procedure Output; Xuất mảng Color[i] là màu của đỉnh i ra file. Function Degree(x:byte):byte; Tính bậc của đỉnh x, bậc của đỉnh x là số đỉnh chưa bị nhập vào đỉnh khác (hay Merge[I]=false) có cạnh nối với x (M[x,i]=true). Function MaxDegree:byte; Trả lại đỉnh chưa được tô màu (Color[i]=0) và có bậc lớn nhất (Degree(i) * Max). Function NumIntermediate(x,y:byte):byte; Trả về số đỉnh trung gian giữa hai đỉnh x và y (Đỉnh i là trung gian của x và y (i<>x; i<>y; Merged[i]=false; M[x,i]=true và M[i,y]=True) Function MaxIntermediate(x:byte):byte; Trả về đỉnh có số đỉnh trung gian với đỉnh x là lớn nhất. NumIntermediate(x,I) * Max. Function Merge(i,x:byte); Nhập đỉnh I vào đỉnh x. Tìm tất cả các đỉnh chưa nhập vào đỉnh nào có cạnh nối với đỉnh i (Merged[j]=false; M[i,j]=true), nối đỉnh đó với đỉnh x (M[j,x]:=true;M[x,j]:=true), xoá cạnh nối giữa đỉnh đó với đỉnh i (M[i,j]:=0;M[j,i]=0). Function NonMaxDegree(x:byte):byte; Tương tự như hàm MaxDegree, tìm đỉnh khác đỉnh x (i<>x), không có cạnh nối với x (M[i,x]=false) có bậc lớn nhất (Degree(i) * Max). Chương trình chính: Pascal Code:Lựa chọn code | Ẩn/Hiện codeProcedure main;var ncol,m,i,mx:byte;Begin input; ncol:=0;{Đặt màu ban đầu bằng 0} m:=MaxDegree;{m là đỉnh có bậc lớn nhất} while(m<>0) do {Nếu đồ thị chưa rỗng} begin inc(ncol);{Tăng màu, sắc số đồ thị tại vòng lặp này} color[m]:=ncol;{tô màu đỉnh m} mx:=MaxIntermediate(m); {mx là đỉnh có số đỉnh trung gian với đỉnh m là lớn nhất} if (mx=0) then mx:=Non_MaxDegree(m);{Không tìm được đỉnh có đỉnh trung gian với đỉnh m, tìm đỉnh không kề với m có bậc lớn nhất} while(mx<>0) do begin Merge(mx,m);{Nhập mx vào m} color[mx]:=ncol; {Tô màu cho đỉnh mx, mx có cùng màu với đỉnh m} mx:=MaxIntermediate(m); if (mx=0) then mx:=Non_MaxDegree(m); {Tiếp tục tìm đỉnh mx như trên cho đến khi không còn tìm được nữa} end; m:=MaxDegree;{m là đỉnh có bậc lớn nhất trong đồ thị còn lại, nếu m=0 thì đồ thị đã rỗng và việc tô màu đã hoàn thành} end; Cromatic:=ncol;{Đặt sắc số của đồ thị là ncol} Ouput;End;Thuật toán trên không phải là một thuật toán tốt trong mọi trường hợp, nhưng nó cố gắng để tìm một giải pháp có thể chấp nhận được để tìm sắc số cho đồ thị. (Còn nữa) Ứng dụng thuật toán tô màu đồ thị Lê Thanh Hà (Tiếp theo số trước) Thuật toán xếp các nhóm thi vào các phòng thi (Thuật toán 2): Sắp xếp các nhóm thi tăng dần theo số lượng thí sinh trong nhóm e1, e2, ., en. Kí hiệu |ei| là số lượng của nhóm ei. Tương tự sắp xếp các phòng theo thứ tự tăng dần theo kích cỡ R1, R2, ., Rn. Kí hiệu |Ri| là độ lớn của phòng thi Ri. Bước 1: Đặt i=1 , j=1, D1=phi. Bước 2: Nếu |ei| =< |Rj| thì thêm ei vào Rj. Ngược lại đặt j=j+1, lặp lại Bước 2. Bước 3: Đặt k = j. Bước 4: Nếu ³ |Rk|, tìm tập các nhóm trong Rk sao cho tổng số số lượng của các nhóm lớn nhất, nhưng chứa được trong Rk hay. Nếu k=m đặt Di+1 = Di hợp {các nhóm còn lại} Ngược lại đặt chúng vào Rk+1, k = k+1, Di+1 = Di và lặp lại bước 4. Bước 5: Đặt i = i+1. Nếu i =< n, lặp lại bước 2. Thuật toán bắt đầu xếp lần lượt từ nhóm nhỏ nhất trong danh sách vào các phòng. Thuật toán đặt mỗi nhóm vào phòng nhỏ nhất có thể chứa nó. Nếu số lượng thí sinh trong phòng đó lớn hơn khả năng chứa của phòng, thuật toán sẽ đẩy một số ít thí sinh nhất lên phòng có kích thước lớn hơn. Nếu số phòng đã hết trong khi số nhóm vẫn còn, thì số nhóm đó sẽ được đặt trong tập DUD (tập Di ở vòng lặp cuối cùng), tập DUD chứa những nhóm không thể xếp vào các phòng trong đợt thi này. Cài đặt: Cấu trúc dữ liệu Mảng 1 chiều chứa kích thước của n nhóm đã được sắp xếp tăng dần: E, E[i] là số thí sinh trong nhóm i. Mảng 1 chiều chứa sức chứa của m phòng đã được sắp xếp tăng dần: R, R[i] là sức chứa của phòng i. Mảng 1 chiều xác định nhóm thuộc phòng: p, p[i] là chỉ số phòng mà nhóm i thuộc. P[I]=DUD=m+1 nếu phòng đó không được xếp vào một phòng nào cả. Các thủ tục và hàm sử dụng trong chương trình: procedure input; Nhập hai mảng E vả R, khởi tạo tất cả các phòng đều chưa được xếp (p[i]=0). Chú ý: phòng chưa được xếp khác với phòng không được xếp (p[i]=DUD) procedure output; Xuất mảng p thể hiện nhóm nào đã được xếp vào phòng nào.Pascal Code:L ựa chọn code | Ẩ n/Hi ệ n code procedure PushUp(k:byte; sum:integer);{Đẩy nhóm lên phòng có kích thước lớn hơn} var i:byte;Begin for i:=1 to n do if (p[i]=k) and (sum-e[i]<=r[k]) then {Tìm một nhóm thuộc phòng k sao cho nếu loại nhóm đó đi thì phòng đó chứa đủ số nhóm còn lại} begin if (k<m) then{Nếu chưa phải là phòng cuối cùng} p[i]:=k+1{đẩy nhóm lên phòng cao hơn} else p[i]:=DUD;{Không xếp phòng cho nhóm này, đẩy nhóm này vào tập DUD} break; end;End;{Chú ý: ở đây ta chỉ xét việc đẩy 1 phòng ra, nếu muốn bạn có thể cài đặt đẩy số nhiều nhóm ra hơn sao cho tổng số thí sinh được đẩy ra là nhỏ nhất, càng ít thí sinh bị đẩy ra thì càng tốt} function SumK(k:byte):integer; Tính tổng số thí sinh trong phòng k. Chương trình chính:Pascal Code:L ựa chọn code | Ẩ n/Hi ệ n code procedure main; var i,j,k,t:byte; sum:integer;Begin Input; for i:=1 to n do {Bắt đầu từ nhóm có số thí sinh nhỏ nhất} begin for j:=1 to m do if (e[i]<=r[j]) then {Tìm phòng nhỏ nhất có thể chứa được nhóm i} begin p[i]:=j; {Đặt nhóm i vào phòng j} break; end; k:=j; sum:=SumK(k); {Tính số thí sinh trong phòng k} while (sum>r[k]) do {Nếu số thí sinh lớn hơn khả năng chứa của phòng k} begin PushUp(k,sum);{Đẩy một số nhóm lên phòng có sức chứa lớn hơn} inc(k); sum:=SumK(k);{Làm tương tự đối với phòng trên} end; end; Ouput;end;Lập lịch thi theo hai thuật toán trên Hai thuật toán trên đã được xây dựng xong. Thuật toán thứ nhất dùng để phân chia các nhóm thành những tập hợp độc lập với nhau. Thuật toán thứ hai sẽ xếp các tập đó vào các phòng thích hợp. Ta có thể sử dụng cả hai thuật toán để được một công cụ xếp lịch thi tương đối tốt.Cho một số phòng thi, cho các nhóm thi và các ràng buộc của chúng được thể hiện trên đồ thị G. Mỗi nhóm là một đỉnh của đồ thị, hai đỉnh có cạnh nối với nhau nếu hai nhóm tương ứng xung đột nhau. Đồ thị G là dữ liệu vào. Bước 1: Đặt p = 1. Bước 2: Dùng thuật toán 1 để tìm ra một tập các nhóm không xung đột với nhau, tập I.Bước 3: Từ tập I, sử dụng thuật toán 2 để đặt mỗi nhóm trong I vào phòng thích hợp. Những nhóm chưa được xếp (nằm trong DUD) sẽ được xếp trong đợt thi sau. Bước 4: Đặt p = p+1. Bước 5: Xoá tất cả các đỉnh (và các cạnh nối đến chúng) trong I trừ các đỉnh có nhóm tương ứng nằm trong DUD, ta có đồ thị G’. Nếu G’ là một đồ thị rỗng, việc xếp thời khoá biểu hoàn thành.Bước 6: Bắt đầu với từ đỉnh được nhập bởi nhiều đỉnh mà nhóm tương ứng có trong DUD. Nếu DUD rỗng chọn đỉnh có bậc lớn nhất. Sử dụng thuật toán 1 để tạo tập I mới có từ đồ thị G’. Đặt G = G’, Quay lại bước 3. Thuật toán trên là tổng hợp của hai thuật toán đã trình bày trước. Cài đặt thuật toán này không quá khó khăn. Bạn có thể tự mình cài đặt được. Bài toán xếp lịch, cụ thể là bài toán xếp lịch thi tuy đã được chứng minh là thuộc lớp bài toán NP-đầy đủ (NP-complete), nhưng nếu biết sử dụng một một chiến thuật thuật toán hợp lý cùng với sự phát triển như vũ bão của công nghệ máy tính bài toán trên cũng phần nào đã được giải quyết. (Nguồn: Báo Tin Học Nhà Trường, tác giả Lê Thanh Hà) . Bài toán xếp lịch 18 Tháng Ba 201111:48 SA Ứng dụng thuật toán tô màu đồ thị để giải quyết Bài toán xếp lịch Giới thiệu bài toán Bài toán xếp lịch. thuật toán này không quá khó khăn. Bạn có thể tự mình cài đặt được. Bài toán xếp lịch, cụ thể là bài toán xếp lịch thi tuy đã được chứng minh là thuộc lớp bài