Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 13

TRƯỜNG ĐẠI HỌC CÔNG NGHỆ GIAO THÔNG VÂN TẢI

KHOA CÔNG NGHỆ THÔNG TIN




MÔN: TRÍ TUỆ NHÂN TẠO

BÁO CÁO BÀI TẬP NHÓM 1


ĐỀ TÀI: BÀI TOÁN PHÂN VIỆC

Giáo viên: Nguyễn Thị Thu Hằng Thành viên nhóm:


Lớp: 70DCTT21 1. Nguyễn Văn Huy
Nhóm thực hiện: Nhóm 1 2. Bùi Anh Quang
3. Đỗ Đăng Thịnh
4. Bùi Đức Dũng

HÀ NỘI – 09/2021
I. Giới thiệu bài toán:

1. Mô tả bài toán:

Có n chi tiết máy J1, J2, ..., Jncần gia công lần lượt trên 3 máy A, B, Cvới thời
gian hoàn thành tương ứng của 1 chi tiết là T A, TB, TC. Các chi tiết từ J1, J2, ..., Jn có
thể gia công theo thứ tự bất kỳ tuy nhiên một chi tiết J i phải được gia công lần
lượt theo thứ tự trên máy A  máy B  máy C.
Trình bày thuật toán và viết chương trình mô tả sao cho tổng thời gian gia công
hoàn thành n chi tiết là thấp nhất (tối ưu). Dữ liệu được đọc từ file có dạng như
sau:
DULIEU.INP
n //số chi tiết cần gia công
J1A, J2A,...., JnA //thời gian gia công các chi tiết trên máy
A
J1B, J2B,...., JnB //thời gian gia công các chi tiết trên máy
B
J1C, J2C,...., JnC //thời gian gia công các chi tiết trên máy
C
Kết quả xuất ra là thứ tự các công việc

2. Thuật toán:
Bài toán gia công với 3 máy A, B, C.
+) Thuật toán Johnson:
Nội dung của thuật toán có thể trình bày đơn giản như sau: đầu tiên ghi dữ
liệu của bài toán vào một bảng n cột, 2 dòng, trong đó mỗi cột ứng với một chi
tiết, dòng đầu ghi các thời gian ai (máy A), dòng thứ hai ghi các thời gian bi
(máy B) như thí dụ đã trình bày:
Chi 1 2 … n n
tiết … -
1
Máy a a … a a
A 1 2 … n n

1
Máy b b … b b
B 1 2 … n n

sau đó chuẩn bị một băng gồm n ngăn để trống và lần lượt xếp mỗi chi tiết vào
một ngăn theo các bước sau (bắt đầu từ bảng thời gian đã cho):
1) tìm giá trị bé nhất của bảng, nếu giá trị này thuộc dòng máy A (dòng 1)
thì xếp chi tiết tương ứng vào ngăn bên trái nhất (còn rỗng) của băng, nếu giá trị
này thuộc dòng máy B (dòng 2) thì xếp chi tiết tương ứng vào ngăn bên phải nhất
(còn rỗng) của băng.
2) xóa cột ứng với chi tiết ra khỏi bảng và lặp lại bước 1) cho đến khi tất cả
các chi tiết đều được xếp. Khi kết thúc, lịch tối ưu được đọc từ trái sang phải của
băng. Nếu ký hiệu x1, x2, ..., xn là các chi tiết được xếp theo lịch thì thuật toán
trên có thể biểu diễn bằng đoạn chương trình sau:
left := 1; {khởi động vị trí đầu trái}
right := n; {khởi động vị trí đầu phải}
WHILE (left ≤ right) DO BEGIN (tìm giá trị bé nhất của bảng và giả sử giá
trị này đạt được tại dòng i và cột ứng với chi tiết j);
IF (i = 1) THEN {thuộc dòng máy A}
BEGIN
xleft := j; left := left +1; {xếp chi tiết j vào ngăn bên trái nhất của
băng}
END ELSE {thuộc dòng máy B}
BEGIN
xright := j; right := right -1; {xếp chi tiết j vào ngăn bên phải nhất của
băng}
END;
(xóa cột ứng với chi tiết j ra khỏi bảng);
END;
Thuật toán gồm một vòng lặp n lần (mỗi lần xếp xong một chi tiết). Mỗi
vòng lặp chủ yếu là thao tác tìm giá trị bé nhất của một tập hữu hạn (ban đầu gồm
2n phần tử, sau mỗi lần lặp lại bớt đi 2 phần tử), vì thế không kể các phép gán và
phép dịch chuyển chỉ số, thuật toán gồm 2n + (2n − 2) + ... + 2 = n(n + 1) phép so
sánh, một khối lượng tính toán rất ít so với việc duyệt toàn bộ.

Chú ý: Việc tính T(X) chỉ cần thực hiện một lần đối với lịch tối ưu X đã được
tìm.
Với thí dụ đã nêu, kết quả từng bước tính theo thuật toán Johnson được
trình bày trên bảng thời gian và băng xếp các chi tiết như sau (giá trị bé nhất tìm
được của bảng, được khoanh trong cặp ngoặc tròn):
Bước 1: Bảng thời gian

C
h
i
ti
ết
M
á
y
A
M (2)
á
y
B

Băng xếp các chi tiết:

Bước 2: Bảng thời gian


C 1 2 3 4
hi
tiế
t
M (3 4 6 5
áy )
A
M 3 3 7 3
áy
B

Băng xếp các chi tiết:

1 3

Bước 3: Bảng thời gian


Ch 2 4 5
i
tiết
M 4 5 6
áy
A
M ( 7 3
áy 3
B )

Băng xếp các chi tiết:


1 2 3

Bước 4: Bảng thời gian


Chi 4 5
tiết
Máy 5 6
A
Máy 7 (
B 3
)

Băng xếp các chi tiết:

1 5 2 3

Bước 5: Bảng thời gian

Chi 4
tiết
Máy (
A 5
)
Máy 7
B

Băng xếp các chi tiết:


1 4 5 2 3

Băng xếp các chi tiết cuối cùng cho lịch tối ưu X* = (1, 4, 5, 2, 3) và thời điểm
hoàn thành của nó được tính từ bảng sau

lị 1 4 5 2 3
c
h
X
*
T 3 8 1 1 2
A ( 4 8 4
i)
T 6 1 1 2 2
B ( 5 8 1 6
i)
Nghĩa là T(X* ) = 26. Thời gian máy B phải chờ theo lịch này là 3 + 2 + 3
= 8. Với thí dụ này bạn đọc cũng thấy khối lượng tính toán là rất ít so với việc phải
duyệt 120 lịch và phải tính tất cả các thời điểm hoàn thành của chúng.
Mở rộng bài toán cho 3 máy:
Dễ dàng mở rộng phát biểu của bài toán tìm lịch gia công trên 2 máy cho
nhiều máy. Đơn giản nhất là cho 3 máy như sau: “Có n chi tiết (đánh số từ 1 đến
n) cần được lần lượt gia công trên 3 máy, đầu tiên qua máy A, sau đó đến máy B,
cuối cùng mới đến máy C. Giả thiết biết thời gian gia công chi tiết i tương ứng
trên các máy A, B, C là ai, bi, ci (i = 1, 2, ..., n). Hãy tìm một lịch gia công (thứ tự
gia công) để thời điểm hoàn thành tất cả các chi tiết là sớm nhất”. Điều đáng chú
ý là, mặc dù việc mở rộng bài toán là đơn giản và tự nhiên, nhưng hiện nay chưa
có một thuật toán hữu hiệu nào kiểu như thuật toán Johnson cho trường hợp 3
máy hoặc nhiều hơn. Trong trường hợp tổng quát, người ta vẫn phải dùng giải
pháp duyệt toàn bộ có đánh giá nhánh cận.
Tuy nhiên, trong trường hợp 3 máy, một số trường hợp riêng có thể dẫn về
bài toán 2 máy như định lý dưới đây (không chứng minh): Định lý. Nếu bài toán
3 máy A, B, C thỏa mãn điều kiện:
max {bi} ≤ min {ai} hoặc max {bi} ≤ min {ci}
(nghĩa là thời gian gia công của máy B khá nhỏ so với thời gian gia công
của máy A hoặc máy C) thì lịch tối ưu của nó trùng với lịch tối ưu của bài toán 2
máy A’, B’ với các thời gian tương ứng a’i = ai + bi và b’i = bi + ci (chú ý rằng chỉ
có lịch tối ưu của chúng là trùng nhau còn thời điểm hoàn thành của chúng là
khác nhau).
Ví dụ: Xét bài toán 3 máy A, B, C:
Ch 1 2 3 4 5
i
tiế
t
M 7 11 8 7 6
áy
A
M 6 5 3 5 3
áy
B
M 4 12 7 8 3
áy
C

ta có max {bi} = 6, min {ai} = 6. Bài toán đã cho thỏa mãn điều kiện đưa về 2 máy
A’, B’ với bảng thời gian:

C
hi
ti
ết
M 13 16 11 12
áy
A

M 10 17 10 13
áy
B

Giải bài toán 2 máy này theo thuật toán Johnson ta được lịch tối ưu X* = (4, 2, 3,
1, 5). Thời điểm hoàn thành của lịch này được tính theo bảng thời gian 3 máy bằng
các công thức truy hồi:
(1) TA(i) = TA(i−1) + ai , i = 1, 2, ..., n với giá trị ban đầu TA(0) = 0
(2) TB(i) = max{TB(i − 1), TA(i)} + bi , i = 1, 2, ..., n với giá trị ban đầu TB(0) = 0
(3) TC(i) = max{TC(i − 1), TB(i)} + ci , i = 1, 2, ..., n với giá trị ban đầu TC(0) = 0
lịc 4 2 3 1 5
h
X*
TA 7 18 26 33 39
(i)
TB 12 23 29 39 42
(i)
TC 20 35 42 46 49
(i)

và nhận được kết quả T(X*) = TC(5) = 49. Qua việc mở rộng vừa trình bày, ta
cũng nhận thấy một điều là, trong việc giải các bài toán tối ưu tổ hợp, thuật toán
càng hiệu quả thì tính riêng biệt của nó càng lớn.
3. Chương trình:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class Bai3phancong {

private
static int n;
static int[][] array;
static int[] group1, group2;
public static void load() throws IOException
{

try {
File f = new File(“C:\\Users\\PC\\Desktop\\baitap-AI\\demo.txt”);
FileReader fr = new FileReader(f);
BufferedReader bf = new BufferedReader(fr);
n = readbuffer(bf);
array = new int[3][n];
for(int i = 0; i < 3; i ++)
for(int j = 0; j < n; j ++)
array[i][j] = readbuffer(bf);
} catch (FileNotFoundException e) {
//Hiển thị chính xác dòng bị lỗi
e.printStackTrace();
}

public static void calculate()


{
group1 = new int[n];
group2 = new int[n];
int i = 0, x = 0, y = 0;
for(i = 0,x = 0, y = 0; i < n; i ++)
{
if(array[0][i] + array[1][i] < array[1][i] + array[2][i])
{
group1[x] = i;
x++;
}
else
{
group2[y] = i;
y++;
}
}
sapxepgroup1(x);
sapxepgroup2(y);
for(i = 0; i < x; i ++)
System.out.print(group1[i] +"->");
for(i = 0; i < y-1; i ++)
System.out.print(group2[i] + "->");
System.out.println(group2[i]);
}

public static void sapxepgroup1(int count)


{
int temp;
for(int i = 0; i < count; i ++)
for(int j = i + 1; j < count; j ++)
if(group1[i]>group1[j]){
temp = group1[i];
group1[i] = group1[j];
group1[j] = temp;
}
}
public static void sapxepgroup2(int count)
{
int temp;
for(int i = 0; i < count; i ++)
for(int j = i + 1; j < count; j ++)
if(group2[i]<group2[j]){
temp = group2[i];
group2[i] = group2[j];
group2[j] = temp;
}
}
public static int readbuffer(BufferedReader bf) throws IOException
{
int result = 0;
int i = bf.read();
while (!isNumber(i))
i=bf.read();
do
{
result*=10;
result+=i-48;
i=bf.read();
}
while (isNumber(i));
return result;
}

public static boolean isNumber(int c)


{
return (c>=48&&c<=57);
}

public static void main(String[] args) throws IOException {


load();
calculate();
}

You might also like