Bài toán xếp lịch
Trang 1Bài toán xếp lịch
18 Tháng Ba 2011
11: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
Trang 2- 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, y
hoặ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)
Trang 3
(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ợp
khô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
Trang 4Procedure 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 code
Procedure 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}
Trang 5end;
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:
Trang 6Cấ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,,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;
Trang 7end;
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à)