Bài giảng Kỹ thuật lập trình - Chương 4:Phương pháp quy hoạch động trình bày các nội dung: Ý tưởng và nguyên lý, công thức truy hồi, một số bài toán quy hoạch động. Cuối chương có phần bài tập để người đọc ôn luyện và vận dụng kiến thức đã học.
Trang 1Chương 4 Phương pháp quy hoạch động
TRẦN MINH THÁI – minhthai@huflit.edu.vn - www.minhthai.edu.vn
Trang 24.1 Ý tưởng và nguyên lý
4.2 Công thức truy hồi
4.3 Một số bài toán quy hoạch động
4.4 Tóm tắt chương
4.5 Bài tập
Nội dung
Trang 3Một ví dụ giới thiệu về bài toán quy hoạch:
Trang 4Những điểm (x, y) thỏa điều kiện x2+y2<=1 là những điểm có tọa độ nằm trong hình tròn có tâm O (gốc tọa độ) và bán kính R=1
Vì thế, nghiệm cần tìm phải nằm trong hình tròn (O, 1)
[4.1] Ý tưởng và nguyên lý
Trang 5Những đường thẳng có phương trình x + y = C là những đường thẳng vuông góc với đường phân giác thứ nhất
Trang 6R=1
phân giác thứ nhất
tiếp tuyến
[4.1] Ý tưởng và nguyên lý
Trang 7Bài toán trên gọi là tối ưu (bài toán quy hoạch) Trong đó:
Có một hàm ƒ gọi là hàm mục tiêu (hay đánh giá)
Một số hàm cho giá trị luận lý ǥ1, ǥ2, , ǥn (hàm ràng buộc)
Trang 8Với bài vừa xét ở trên, ta có:
Hàm ƒ: ƒ(x,y) = x+y
Hàm ràng buộc ǥ: x2+y2<=1
Một nghiệm x là tốt nhất với ý nghĩa là lớn nhất
Các bài toán quy hoạch rất phong phú, đa dạng và nhiều ứng dụng thực tế Tuy nhiên có một số bài toán chưa giải được
[4.1] Ý tưởng và nguyên lý
Trang 9Richard Bellman phát minh - 1953
Ý tưởng của nguyên lý tối ưu Bellman là
“Với mỗi quá trình điều khiển tối ưu, đối với trạng thái bắt đầu A 0 , với trạng thái A trong quá trình đó, phần quá trình kể từ trạng thái A xem như trạng thái bắt đầu cũng là tối ưu”.
“Nếu một cấu hình là tối ưu thì mọi cấu hình con của nó cũng là tối ưu”.
Phương pháp quy hoạch động
Trang 10Dùng để giải các bài toán tối ưu có bản chất là đệ quy:
Việc tìm phương án tối ưu có thể đưa về tìm tối ưu cho các bài toán con hữu hạn
Thuật toán đệ quy đã tìm hiểu ở chương 3 đa số là dùng nguyên lý “chia để trị” và trong quy hoạch động cũng áp dụng nguyên lý này
Phương pháp quy hoạch động
Trang 11Phép phân giải đệ quy theo hướng top-down:
Bắt đầu từ bài toán lớn phân rã thành bài toán con
Đi giải từng bài toán con Việc giải bài toán con lại đưa
về phép phân rã tiếp thành các bài toán con nhỏ hơn
Phép phân giải đệ quy theo hướng bottom-up:
Bắt đầu giải các bài toán nhỏ (bài toán cơ sở)
Sau đó giải các bài toán lớn hơn (bài toán ban đầu)
Hai loại quy hoạch động
Trang 12Ví dụ: tính số hạng thứ n của dãy Fibonaci như sau:
Hai loại quy hoạch động
Trang 13static int fiBoNaCi_QuyHoach_C1(int n)
Trang 14static int fiBoNaCi_QuyHoach_C2(int n)
{
int []Fn=new int[101];
Fn[0] = Fn[1] = 1;
for (int i = 2; i <= n; i++)
Fn[i] = Fn[i - 1] + Fn[i - 2];
return Fn[n];
}
Hai loại quy hoạch động
Trang 15Bài toán quy hoạch động: là bài toán được giải theo phương pháp quy hoạch động.
Công thức truy hồi của quy hoạch động: là công thức phối hợp nghiệm của các bài toán con để có nghiệm cho bài toán lớn
Bảng phương án của quy hoạch động: là Không gian lưu trữ lời giải của các bài toán con để tìm cách phối hợp chúng
Khái niệm
Trang 16Cần thỏa mãn các yêu cầu sau:
Phải phân rã được bài toán lớn thành các bài toán con và sự phối hợp lời giải đó cho ta lời giải cuối cùng của bài toán lớn
Phải có đủ không gian bộ nhớ vật lý
Quá trình phối hợp lời giải bài toán con đến bài toán ban đầu, phải có một số bước hữu hạn (tính dừng của chương trình)
Các bước cài đặt
Trang 17Bước 1: Phân tích bài toán, lập công thức truy hồi.
Bước 2: Giải tất cả các bài toán con và lưu vào bảng phương án (dùng mảng một chiều hoặc hai chiều)
Bước 3: Dùng công thức truy hồi để phối hợp các lời giải của những bài toán con, lặp cho đến khi tìm được lời giải ban đầu
Bước 4: Dựa vào bảng phương án, truy vết tìm lời giải tối ưu
Các bước cài đặt
Trang 18Ví dụ: Tính
B1: Phân tích bài toán, công thức truy hồi:
Các bước cài đặt
Trang 19B2: Giải bài toán con và lưu vào bảng phương án
Trang 20B3: Tính từ dòng i=2 đến n theo công thức truy hồi sau:
F[i,k]=F[i-1,k]+F[i-1,k-1];
Bảng phương án sau khi thực hiện B3
B4: Kết quả bài toán lưu ở dòng cuối cùng và cột k
Trang 21Công thức truy hồi của quy hoạch động: là công thức phối hợp nghiệm của các bài toán con để có nghiệm cho bài toán lớn
Khi phân tích bài toán và tìm ra công thức truy hồi, ta sẽ phải tìm ra hai thành phần sau:
Phần cơ sở quy hoạch động (giống như phần cố định – neo trong chương 3 về đệ quy)
Phần truy hồi (công thức truy hồi – giống như phần đệ quy của chương 3)
[4.2] Công thức truy hồi
Trang 22Ta xét ví dụ sau: Cho số tự nhiên n<=100 Hãy cho biết có bao nhiêu cách phân tích số n thành tổng của dãy các số nguyên dương.
Với n=5, ta có 7 cách như sau:
Trang 23Lưu ý:
Trường hợp n=0 vẫn tính là một cách (dãy rỗng thì tổng bằng 0)
Không tính hoán các cách phân tích
Liệu có cách nào tính ra ngay mà không phải liệt kê như bảng 4.3 không?
Nếu n=100 thì có 190.569.292 cách phân tích, như thế thì rất chậm
[4.2] Công thức truy hồi
Trang 24Gọi F[m,v] là số cách phân tích số v thành tổng các số nguyên dương <= m.
Các cách phân tích số v thành tổng các số nguyên dương
<= m có thể chia thành hai loại:
Loại 1: Không chứa m trong các phân tích: số cách phân tích số v thành tổng các số nguyên dương < m và bằng F[m-1,v]
Loại 2: Có chứa ít nhất một số m trong phân tích, khi đó nếu bỏ m ta sẽ được các cách phân tích số v=m thành tổng các số nguyên dương <= m Lúc này số cách sẽ bằng F[m,v-m]
Trang 25Trường hợp m>v thì chỉ có loại 1, ngược lại (m<=v) có cả
2 loại Ta có công thức truy hồi sau:
Ta xây dựng công thức F[m,v] từ F[m-1,v] và F[m,v-m], gọi là công thức truy hồi
[4.2] Công thức truy hồi
Trang 26Với n=5, ta có bảng phương án quy hoạch như sau:
Trang 27Nhìn vào bảng phương án, ta nhận xét rằng F[m,v] bằng tổng của:
Một phần tử ở hàng trên, cùng cột: F[m-1,v]
Một phần tử ở cùng hàng, bên trái cột là v-m: m]
Trang 28Nhận xét:
Ta tính dòng trên trước
Trong cùng một dòng thì tính từ trái sang
Cột v=0 thì có một cách
Dòng m=0 thì không có cách nào với mọi v>0
[4.2] Công thức truy hồi
Trang 29static int soCachPhanTichSo(int n)
{ int[,] F = new int[101, 101]; int m, v;
Trang 30Bài toán tìm dãy con đơn điệu tăng dài nhất.
Bài toán chiếc ba lô dạng một
[4.3] Một số bài toán quy hoạch động
Trang 31Mô tả: Cho dãy số nguyên A gồm n phần tử Một dãy con của A là một cách chọn trong A một số phần tử giữ nguyên thứ tự (ta có tổng cộng 2n dãy con) Hãy tìm dãy con đơn điệu tăng của A có độ dài lớn nhất.
Ví dụ: dãy A={5,2,3,4,9,10,5,6,7,8}
Dãy con đơn điệu tăng dài nhất là {2,3,4,5,6,7,8}
Tìm dãy con đơn điệu tăng dài nhất
Trang 32B1: Phân tích và công thức truy hồi:
Bổ sung vào dãy A một phần tử ở đầu A[0] có giá trị - và một phần vào cuối dãy A[n+1] có giá trị là + Như thế dãy đơn điệu sẽ bắt đầu từ A[0] và kết thúc là A[n+1]
Tạo thêm dãy phụ có tên L với kích thước bằng dãy A, với mỗi phần tử dãy L[i] có giá trị là độ dài dãy con đơn điệu tăng dài nhất bắt đầu tại A[i] (0<=i<=n+1)
Ta tính tất cả các L[i] này
Kết quả bài toán là tìm giá trị lớn nhất trên dãy L này (L[vtmax])
Trang 33Cơ sở quy hoạch động (bài toán nhỏ nhất)
Trường hợp đặc biệt: L[n+1] là độ dài dãy con đơn
điệu tăng dần dài nhất bắt đầu tại A[n+1] = +
Vậy dãy con này chỉ có một phần tử là +, nên
L[n+1]=1
Trang 34Công thức truy hồi:
Tính L[i] với i chạy từ n trở về 0 Giá trị L[i] được tính khi khi L[i+1], , L[n+1] đã biết
Phần tử đang xét của dãy A là A[i] sẽ được tính vào dãy con đơn điệu dài nhất nếu:
A[i]<A[j] (bảo đảm tính tăng) Với điều kiện j là vị trí sau i, nghĩa là j đi từ i+1 đến n+1
Chọn ra chỉ số jmax có L[jmax] là lớn nhất
Trang 35Công thức truy hồi sau:
L[i] = L[jmax] + 1
hoặc: L[i]= max{L[j]+1, với i<j<=n+1 và a[i]<A[j]}
Trang 37B3: Truy vết:
Sau khi tính đồng hành hai dãy L và T, ta sẽ bắt đầu từ T[0]
và có kết quả như sau:
Trang 38Tập tin DATA.INP:
Dòng 1: Số phần tử của dãy n=10
Dòng 2: n (10) số cách nhau bởi khoảng trắng
Tập tin DAYCONTANG.OUT:
Dòng 1: Độ dài dãy con tăng
Dòng 2: các phần tử trong dãy con tăng
1 2
Trang 39static bool docFile(ref int[]A,string fileName)
{ StreamReader sr = new StreamReader(fileName);
if( sr == null)
{ Console.WriteLine("Loi khi doc file"); return false; }
int n = int.Parse(sr.ReadLine()); A = new int[n + 2];
string S = sr.ReadLine();
string[] M = S.Split(new Char[] { ' ' }); int j = 0;
for (int i = 1; i <= n; i++)
{ while (M[j] == "") j++;
A[i] = int.Parse(M[j++]);
}
return true;
Trang 40static void taoBangPhuongAn(int[]A,out int []L,out int[]T)
Trang 41static bool truyVet (int[] A, int[] L, int[] T, string fileName)
Trang 42static void Main(string[] args)
{
int[] A = null, L, T;
if(docFile(ref A,"DATA.INP")==true)
{
taoBangPhuongAn(A, out L, out T);
if (truyVet (A, L, T, "DAYCONTANG.OUT") == true)
Console.WriteLine("Luu file thanh cong")
}
}
Trang 43Mô tả:
Có n món đồ, vật thứ i có trọng lượng là w i và giá trị v i
Hãy chọn ra các món có thể bỏ vào ba lô có trọng lượng
tối đa là W sao cho tổng các giá trị các món đồ là lớn
Bài toán chiếc ba lô dạng một
Trang 44Gọi F[i, j] là giá trị lớn nhất có thể có bằng cách chọn trong các món {1,2, ,j} với giới hạn trọng lượng j
Như vậy F[n, W] chính là giá trị lớn nhất khi được chọn trong số n gói với giới hạn trọng lượng W
Cách giải
Trang 45B1: Công thức truy hồi tính F[i, j]
Với giới hạn trọng lượng j, việc chọn phương án tối ưu trong số các gói {1, 2, , i-1, i}, để có giá trị lớn nhất có 2 khả năng:
Không chọn gói thứ i: F[i, j] = F[i-1, j].
Chọn gói thứ i (w i<=j): F[i, j]=vi + F[i-1, j – w i].
Chọn F[i, j] là giá trị lớn nhất trong hai giá trị thu được ở trên.
Cơ sở quy hoạch động:
Trang 46Dòng đầu tiên: cơ sở quy hoạch động, toàn bộ bằng 0
Dòng thứ hai đến dòng thứ n: dùng công thức truy hồi
Trang 542 3 4 5 6
Trang 55static bool docFile(ref int[] w, ref int[]v, ref int n, ref int W, string fileName)
{ StreamReader sr = new StreamReader(fileName);
string S = sr.ReadLine();
string[] M = S.Split(new Char[] { ' ' }); int j = 0;
while (M[j] == "") j++; n = int.Parse(M[j++]);
while (M[j] == "") j++; W = int.Parse(M[j++]);
w = new int[n + 1]; v = new int[n + 1];
for (int i = 0; i < n; i++)
{ S = sr.ReadLine(); M = S.Split(new Char[] { ' ' }); j = 0;
while (M[j] == "") j++; w[i] = int.Parse(M[j++]);
while (M[j] == "") j++; v[i] = int.Parse(M[j++]);
}
Trang 56static void bangPhuongAn(int[] w, int[] v, int n, int W, out int[,] F) {
Trang 57static bool truyVet (int[]w, int[]v, int n, int W, int[,]F, string fName) {
StreamWriter sw = new StreamWriter(fName);
Trang 58static void Main(string[] args)
{
int[] w=null, v=null; int n=0, W=0; int[,] F;
if (docFile(ref w,ref v,ref n,ref W," // //BALO.INP") ==true) {
bangPhuongAn(w, v, n, W, out F);
if (truyVet (w,v,n,W,F," // //BALO.OUT") == true)
Console.WriteLine("Luu file thanh cong");
}
Console.ReadLine();
}
Trang 59Phương pháp quy hoạch động do nhà toán học Richard Bellman phát minh vào năm 1953
Ý tưởng của nguyên lý tối ưu Bellman là:
“Với mỗi quá trình điều khiển tối ưu, đối với trạng thái bắt đầu A 0 , với trạng thái A trong quá trình
đó, phần quá trình kể từ trạng thái A xem như trạng thái bắt đầu cũng là tối ưu”.
[4.4] Tóm tắt chương
Trang 60Phương pháp quy hoạch động thường được dùng để giải các bài toán tối ưu có bản chất là đệ quy:
Việc tìm phương án tối ưu có thể đưa về tìm tối ưu cho các bài toán con hữu hạn
Thuật toán đệ quy đã tìm hiểu ở chương 3 đa số là dùng nguyên lý “chia để trị” và trong quy hoạch động cũng áp dụng nguyên lý này
[4.4] Tóm tắt chương
Trang 61Có 2 loại quy hoạch động:
Phép phân giải đệ quy theo hướng “từ trên xuống” (top-down)
Phép phân giải đệ quy theo hướng “từ dưới lên” (bottom-up)
[4.4] Tóm tắt chương
Trang 62Ta có một số khái niệm sau:
Bài toán quy hoạch động: giải theo phương pháp quy hoạch động
Công thức truy hồi của quy hoạch động: là công thức phối hợp nghiệm của các bài toán con để có nghiệm cho bài toán lớn
Bảng phương án của quy hoạch động: là không gian lưu trữ lời giải của các bài toán con để tìm cách phối hợp chúng
[4.4] Tóm tắt chương
Trang 63Muốn giải bằng phương pháp quy hoạch động, bài toán cần thỏa mãn các yêu cầu sau:
Phải phân rã được bài toán lớn thành các bài toán con và sự phối hợp lời giải đó cho ta lời giải cuối cùng của bài toán lớn
Phải có đủ không gian bộ nhớ vật lý
Quá trình phối hợp lời giải bài toán con đến bài toán ban đầu, phải có một số bước hữu hạn (tính dừng của chương trình)
[4.4] Tóm tắt chương
Trang 64Các bước cài đặt:
Bước 1: Phân tích bài toán, lập công thức truy hồi
Bước 2: Giải tất cả các bài toán con và lưu vào bảng phương án (dùng mảng một chiều hoặc hai chiều)
Bước 3: Dùng công thức truy hồi để phối hợp các lời giải của những bài toán con, lặp cho đến khi tìm được lời giải ban đầu
Bước 4: Dựa vào bảng phương án, truy vết tìm lời giải tối ưu
[4.4] Tóm tắt chương
Trang 65Cũng gần giống như phần đệ quy ở chương 3: khi phân tích bài toán và tìm ra công thức truy hồi, ta sẽ phải tìm
Trang 66Bài 1: Bài toán bố trí phòng họp
Có n cuộc họp, cuộc họp thứ i bắt đầu vào thời điểm s i
và kết thúc f i
Do chỉ có một phòng hội thảo nên hai cuộc họp bất kỳ sẽ được cùng bố trí phục vụ nếu khoảng thời gian làm việc của các cuộc họp này chỉ giao nhau tại các đầu mút
Hãy bố trí lịch họp sao cho phục vụ được nhiều cuộc họp nhất
[4.5] Bài tập
Trang 67Bài 2: Bài toán điền dấu biểu thức
Cho n số tự nhiên a1, a2, , an Ban đầu các số được đặt liên tiếp theo đúng thứ tự cách nhau bởi dấu chấm hỏi (?) như sau: a1 ? a2 ? ? , an
Cho trước số nguyên S, có cách nào thay các dấu chấm hỏi bằng dấu công (+) hoặc trừ (-) để được một biểu thức
số học cho giá trị là S không?
Ví dụ: dãy ban đầu 1 ? 2? 3 ? 4 với K=0, thì cho kết quả 1-2-3+4 = 0
[4.5] Bài tập
Trang 68Bài 3: Bài toán xâu con chung dài nhất.
Xâu ký tự S gọi là xâu con của xâu M nếu có thể xóa bớt một số ký tự trong xâu M để được xâu S
Nhập vào hai xâu ký tự X, Y và tìm xâu Z có độ dài lớn
là xâu con của cả X và Y
Ví dụ: nhập X= “abcdefghi123” và Y= “abc1def2ghi3” thì Z là “abcdefghi3”
[4.5] Bài tập