Tải bản đầy đủ (.pdf) (5 trang)

Phương pháp quy hoạch động

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (421.12 KB, 5 trang )

Phương pháp quy hoạch động
Quy hoạch động - giống như phương pháp chia để trị - giải quyết các bài toán bằng cách kết hợp
các giải pháp của các bài toán con. Điểm khác biệt là một thuật toán quy hoạch động giải quyết
tất cả các bài toán cháu đúng một lần và sau đó ghi kết quả của chúng trong một bảng, như vậy
tránh được việc phải tính lại các kết quả khi bài toán cháu được gặp lại.

1. Nguyên lý tối ưu Bellman

- Quy hoạch động là quá trình điểu khiển tối ưu với trạng thái bắt đầu. Mọi trạng thái A bất kỳ
thuộc quá trình này cũng tối ưu.
- Tư tưởng chính: Thực hiện các bài toán con trước, sử dụng các kết quả này để giải bài toán lớn
- Hướng tiếp cận:
+ Giải bài toán theo công thức truy hồi
+ Giải các bài toán con trước
+ Dựa vào bài toán con để giải bài toán lớn hơn cho đến khi gặp bài toán cần giải
- Tổng quát:
+ Giải bài toán qua N bước
+ Giải bài toán sao cho tổng chi phí 1 -> N-1 và từ N-1 -> N là tối ưu

2. Thuật toán quy hoạch động

Bước 1: Xây dựng công thức truy hồi
Giả sử: Chia bài toán thành N giai đoạn 1->N
Xác định F(1) - cơ sở quy nạp
- Gọi (i) là hàm số xác định giá trị tối ưu, tính đến giá trị thứ i
-> F(n) là nghiệm của bài toán
- Đối với bài toán
+ Tìm Min: F(N) = Min{F(i), F(j)}
i = 1, N-1
j = N-1, N
+ Tìm Max: F(N) = Max{F(i), F(j)}


i = 1, N-1
j = N-1, N

Bước 2: Tìm cơ sở quy hoạch động
Để chia bài toán lớn thành các bài toán con có cùng một cách giải thì phải yêu cầu phải biến đổi
một số bài toán con ở trường hợp cơ sở quy nạp bằng cách thêm biến phụ, chính là cơ sở quy
hoạch động

Bước 3: Lấp đầy bảng phương án, dựa vào cơ sở quy hoạch động, công thức quy hoạch động
Giải bài toán

Bước 4: Truy vết
Tìm nghiệm của bài toán

3. Ví dụ

Bài toán: Dãy con không giảm dài nhất
Phân tích:
- Gọi L[i] là độ dài lớn nhất của dãy con không giảm từ x[i] -> x[n]
-> L[1] là nghiệm của bài toán
- Để đưa các trường hợp này về cùng một cách giải, ta thêm 2 phần tử
+ a[0] = -œ
+ a[n+1] = +œ
Thuật toán:
Bước 1: Xây dựng công thức truy hồi
- Xét tại phần tử thứ i:
+ L[i] = 1 nếu a[i] > > a[n]
+ L[i] = L[jmin] + 1 với jmin = min{j | a[i] < a[j]}
- Tổng quát:
+ L[i] = max {L[j] với j = i+1, n và a[i] < a[j]}


Bước 2: Cơ sở quy hoạch động
L[n+1] = 1

Bước 3: Tính bảng phương án
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void QHD()
{
int i, j;
int jmax, temp;

a[0] = -32766;
a[n+1] = 32767;
L[n+1] = 1;
for(i=n;i>=0; i )
{
jmax = n+1;
temp = L[n+1];
for(j=i+1; j<=n; j++)
if(a[i] < a[j] && L[j] > temp)
{
temp = L[j];
jmax = j;
}
L[i] = L[jmax]+1;
T[i] = jmax;
}
}


Bước 4: Truy vết
- Theo các vết sử dụng mảng T[i] mà ta đã đánh dấu
- Bắt đầu từ T[0] ta lần lượt lưu lại T[i] cho tới khi T[i] = n+1

Post added at 10:55 AM Previous post was at 09:57 AM

Áp dụng thuật toán Quy hoạch động cho bài toán chiếc túi xách
Bài toán: Một tên trộm sau khi đột nhập vào nhà thì thấy có N loại đồ vật có kích thước và giá trị
khác nhau. Vật gì hắn ta cũng muốn mang đi, nhưng lại chỉ mang một chiếc túi có dung lượng M
(có thể chứa được một số đồ vật sao cho tổng kích thước chỉ nhỏ hơn hay bằng M). Vấn đề đặt ra
cho tên trộm là hắn phải chọn lựa một danh sách các đồ vật sẽ mang đi sao cho tổng giá trị lấy

cắp là lớn nhất.
Chúng ta sẽ cùng xét trường hợp tên trộm mang chiếc túi xách có dung lượng ví dụ là 17 và
trong phòng đột nhập có các đồ vật thuộc 5 loại khác nhau mà kích thước và giá trị được liệt kê
như ở hình dưới:

Khi đó tên trộm có thể mang đi 5 đồ vật loại A với tổng giá trị là 20, hay tên trộm có thể chất đầy
túi với một đồ vật là D và một đồ vật là E với tổng giá trị (i) đạt được là cost[i-size[j]] + val[j] (vì
đồ vật j thêm vào sẽ làm đầy phần còn lại của túi có dung lượng I). Nếu giá trị mới này vượt quá
cost[i] (giá trị lớn nhất túi xách dung lượng i có thể đạt được khi không có đồ vật j) thì chúng ta
sẽ cập nhật cost[i] và best[i]. Hình dưới đây sẽ minh hoạ từng bước quá trình tính toán trên ví dụ
của chúng ta:


Nội dung thực sự của phương án tối ưu (danh sách các đồ vật cần bỏ vào túi xách) có thể tìm lại
được dựa vào các giá trịtrong mảng best. Theo định nghiữa, best[M] cho biết đồ vật cuối cùng
phải thêm vào túi xách, vậy đồ vật vừa được bỏ vào túi trước đó là best[M-size[best[M]]], cứ lần
ngược như vậy ta sẽ có danh sách các đồ vật trong túi xách với tổng giá trị lớn nhất. Đối với ví
dụ của chúng ta ở trên, best[17]= C, sau đó ta có best[10]=C và best[3] = A.
*** Thời gian giải quyết bài toán túi xách bằng phương pháp quy hoạch động tỷ lệ với NM.
Do vậy bài toán túi xách có thể giải quyết dễ dàng khi M không quá lớn, nhưng thời gian thi
hành chương trình sẽ trở nên khó chấp nhận khi M lớn. Hơn nữa, có một điểm cốt yếu không thể
bỏ qua đó là phương pháp quy hoạch động không thể thực hiện được nếu M và những kích thước
hay giá trị của các đồ vật là số thực thay vì số nguyên. Đây không phải là rắc rối nhỏ mà là khó
khăn chính của phương pháp này.
Tất nhiên, nếu dung lượng, kích thước và các giá trị của các đồ vật đều là số nguyên, chúng ta có
được một nguyên lý cơ bản là quyết định tối ưu, khi đã được chọn thì không cần thay đổi. Một
khi đã biết cách tốt nhất để bỏ đồ vào túi xách có kích thước bất kỳ với j đồ vật ban đầu, ta
không cần xem xét lại những vấn đề đó nữa, bất kể những đồ vật sẽ chọn tiếp theo là gì. Khi nào
nguyên lý tổng quát này còn hoạt động được, thì phương pháp quy hoạch động còn ứng dụng
được. Trong trường hợp này, nguyên lý hoạt động được ví với các giá trị nguyên ta có thể chọn

được một quyết định chính xác, tối tưu.

Bài toán chiếc túi xách có thể được tổng hợp lại như sau:
Có N loại đồ vật, mỗi loại có số lượng không hạn chế. Đồ vật loại Îi, đặc trưng bởi trọng lượng
Wi và giá trị sử dụng Vi, với mọi i{1, ,n}. Cần chọn các vật này đặt vào một chiếc túi xách có
giới hạn trọng lượng M, sao cho tổng giá trị sử dụng các vật được chọn là lớn nhất.
Dưới đây là cài đặt của thuật toán:
1
2
3
4
5
void Try(int i)
{
int j, t, g;
t = (int)((m-Tl)/w[i]);
for (j = t; j >=0 ; j )
{
6
7
8
9
10
11
12
13
14
15
16
17

18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
x[i] = j;
Tl = Tl + w[i]*x[i]; //Trong luong thu duoc
S = S + v[i]*x[i]; //Gia tri thu duoc
if(i==n) //Cap nhat toi uu
{
if(S > Gttu)
{

Gan();
Gttu = S;
}
}
Else
{
g = S + v[i+1]*(m-Tl)/w[i+1]; //Danh gia can
if ( g > Gttu)
Try(i+1);
}
Tl = Tl - w[i]*x[i];
S = S - v[i]*x[i];
}
}
//*************
void Init()
{
for (int i = 1; i <= n; i++)
{
Patu[i] = 0;
x[i] = 0;
}
S = 0;
Gttu = 0;
Tl = 0;
}

×