2. QUY HOẠCH ĐỘNG 1 Mở đầu
2.4. Bài tốn phân hoạch
Giả sử cĩ 20 file dữ liệu lớn cần lưu trữ, kích thước mỗi file được tính bằng Gigabyte. Tổng kích thước các file là 200 GB. Cĩ 2 đĩa để lưu trữ, mỗi đĩa cĩ dung lượng 100 GB.
Cĩ thể lưu được tất cả các file hay khơng?
Tùy theo tình huống mà câu trả lời là được hoặc khơng. Chẳng hạn nếu cĩ 18 file 5GB, 1 file 47 GB, 1 file 63 GB thì câu trả lời là khơng thể. Hai file lớn nhất khơng thể lưu trên hai đĩa khác nhau vì khi đĩ khơng đĩa nào cĩ tổng dung lượng các file là bội của 10, cũng khơng thể lưu trên cùng một đĩa vì quá lớn.
Ta phát biểu lại bài tốn như sau: Cho số nguyên dương xn 1,..., xn và một số tự nhiên T, cần xác định trong dãy đã cho cĩ thể tìm được các số cĩ tổng bằng T hay khơng (trong bài tốn ban đầu n=20, T=100).
Cĩ thể giải quyết bài tốn này bằng đệ quy. Nếu tìm được các số cĩ tổng bằng T thì xn cĩ thể nằm trong các số này hoặc khơng. Vì vậy câu trả lời là được nếu như trong các số x1,..., x tìm n-1 được các số cĩ tổng bằng T hoặc bằng T-xn. Ta cĩ thuật tốn đệ quy sau:
int PH(int X ,int int T); [] n, If (T<0) { return 0; } Else
If (T=0) { return 1;}
Else { return PH(X,n-1,T) || PH(X,n-1,T-X[n]); }
Như vẫn thường thấy thuật tốn đệ quy này khá đơn giản nhưng lại rất khơng hiệu quả. Nếu X cĩ n phần tử thì cần tới 2n lời gọi đệ quy.
Bây giờ ta sẽ tìm cách giải quyết bài tốn bằng quy hoạch động.
Gọi M(i,j) là khẳng định đúng (M(i,j) =True) nếu cĩ thể tìm được trong x1,.., xi các số cĩ tổng bằng j và sai (M(i,j)=False) nếu ngược lại. Giá trị cần tính là M(n,T).
Ta cĩ M(i,0) = True với mọi i (khơng cần tìm số nào hết). M(i,j) = M -1,j) (i nếu xi > j (vì sẽ khơng thể dùng đến xi) và
M(i,j) = M -1,j) or M(i (i-1,j-xi) nếu xi j (ứng với hai trường hợp: cĩ sử dụng xi và khơng sử dụng xi).
Vậy ta cĩ thuật tốn sau: inht PH2(X,n,T);
for (i=1;i<=n;i++) { M[i,0]=0;
for (j=1;j<=T;j++) {
if (X[i]>j) { M[i,j]=M[i-1,j] ; }
else M[i,j]= M[i-1,j] || M[i-1,j-X[i]]; { } }
}
Return M[n,T];
Cĩ thể cải tiến được một thuật tốn tốt hơn: dùng mảng một chiều M lưu các giá trị logic.
int PH3(X,n,T); M[0]=0;
for (i=1;i<=n;i++) {
for (j=X[i];j<=T;j++) { M[j]= M[j] || M[j-X[i]]; } return M[T];
2.5. Nhân nhiều ma trận (đọc thêm) Giả sử ta cần tính tích các ma trận M=M1M ..M2 n.