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

Bài toán xếp ba lô ppsx

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 (174.1 KB, 6 trang )

Bài toán xếp ba lô
Bài toán xếp ba lô (một số sách ghi là bài toán cái túi, tương tự như bài toán xếp
vali) là một bài toán tối ưu hóa tổ hợp. Bài toán được đặt tên từ vấn đề chọn những
gì quan trọng có thể nhét vừa vào trong một cái túi (với giới hạn khối lượng) để
mang theo trong một chuyến đi.
Một số cách phát biểu nội dung bài toán:
Một kẻ trộm đột nhập vào một cửa hiệu tìm thấy có n mặt hàng có trọng lượng và
giá trị khác nhau, nhưng hắn chỉ mang theo một cái túi có sức chứa về trọng lượng
tối đa là M. Vậy kẻ trộm nên bỏ vào ba lô những món nào và số lượng bao nhiêu
để đạt giá trị cao nhất trong khả năng mà hắn có thể mang đi được.
Một hành khách chỉ được mang theo một vali có khối lượng hàng hoá tối đa là
M. Hành khách đó đã chuẩn bị ra N dồ vật được đánh số từ 1 đến N để chuẩn bị
mang theo. Đồ vật thứ i có trọng lượng là ai và giá trị sử dụng là c
i
(i = 1, 2,
N) Yêu cầu: Chỉ ra đồ vật mà hành khách đó cần mang theo sao cho tổng giá trị sử
dụng là lớn nhất?
Bài toán:
Trong siêu thị có n gói hàng (n ≤ 100), gói hàng thứ i có trọng lượng là W
i
≤ 100
và trị giá V
i
≤ 100. Một tên trộm đột nhập vào siêu thị, tên trộm mang theo một cái
túi có thể mang được tối đa trọng lượng M ( M ≤ 100). Hỏi tên trộm sẽ lấy đi
những gói hàng nào để được tổng giá trị lớn nhất.
Input: file văn bản BAG.INP
• Dòng 1: Chứa hai số n, M cách nhau ít nhất một dấu cách
• n dòng tiếp theo, dòng thứ i chứa hai số nguyên dương Wi, Vi cách nhau ít nhất
một dấu cách
Output: file văn bản BAG.OUT


• Dòng 1: Ghi giá trị lớn nhất tên trộm có thể lấy
• Dòng 2: Ghi chỉ số những gói bị lấy
BAG.INP

BAG.OUT

5 11 11
3 3
4 4
5 4
9 10
4 4
5 2 1

Cách giải:
Nếu gọi F[i, j] là giá trị lớn nhất có thể có bằng cách chọn trong các gói {1, 2, …,
i} với giới hạn trọng lượng j. Thì 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 M chính là F[n, M].
1. 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 tối ưu trong số các gói {1, 2, …,i – 1, i} để
có giá trị lớn nhất sẽ có hai khả năng:
• Nếu không chọn gói thứ i thì F[i, j] là giá trị lớn nhất có thể bằng cách chọn trong
số các gói {1, 2, …, i – 1} với giới hạn trọng lượng là j. Tức là
F[i, j] = F[i - 1, j]
• Nếu có chọn gói thứ i (tất nhiên chỉ xét tới trường hợp này khi mà Wi ≤ j) thì F[i,
j] bằng giá trị gói thứ i là Vi cộng với giá trị lớn nhất có thể có được bằng cách
chọn trong số các gói {1, 2, …, i – 1} với giới hạn trọng lượng j – Wi. Tức là về
mặt giá trị thu được:
F[i, j] = Vi + F[i - 1, j - Wi]
Vì theo cách xây dựng F[i, j] là giá trị lớn nhất có thể, nên F[i, j] sẽ là max trong 2

giá trị thu được ở trên.
2. Cơ sở quy hoạch động:
Dễ thấy F[0, j] = giá trị lớn nhất có thể bằng cách chọn trong số 0 gói = 0.
3. Tính bảng phương án:
Bảng phương án F gồm n + 1 dòng, M + 1 cột, trước tiên được điền cơ sở quy
hoạch động: Dòng 0 gồm toàn số 0. Sử dụng công thức truy hồi, dùng dòng 0 tính
dòng 1, dùng dòng 1 tính dòng 2, v.v… đến khi tính hết dòng n.

4. Truy vết:
Tính xong bảng phương án thì ta quan tâm đến F[n, M] đó chính là giá trị lớn nhất
thu được khi chọn trong cả n gói với giới hạn trọng lượng M. Nếu F[n, M] = F[n -
1, M] thì tức là không chọn gói thứ n, ta truy tiếp F[n - 1, M]. Còn nếu F[n, M] ≠
F[n - 1, M] thì ta thông báo rằng phép chọn tối ưu có chọn gói thứ n và truy tiếp
F[n - 1, M - Wn]. Cứ tiếp tục cho tới khi truy lên tới hàng 0 của bảng phương án.
PROG03_2.PAS * Bài toán cái túi
program The_Bag;
const
max = 100;
var
W, V: Array[1 max] of Integer;
F: array[0 max, 0 max] of Integer;
n, M: Integer;
procedure Enter; {Nhập dữ liệu từ thiết bị nhập chuẩn (Input)}
var
i: Integer;
begin
ReadLn(n, M);
for i := 1 to n do ReadLn(W[i], V[i]);
end;
procedure Optimize; {Tính bảng phương án bằng công thức truy hồi}

var
i, j: Integer;
begin
FillChar(F[0], SizeOf(F[0]), 0); {Điền cơ sở quy hoạch động}
for i := 1 to n do
for j := 0 to M do
begin {Tính F[i, j]}
F[i, j] := F[i - 1, j]; {Giả sử không chọn gói thứ i thì F[i, j] = F[i - 1, j]}
{Sau đó đánh giá: nếu chọn gói thứ i sẽ được lợi hơn thì đặt lại F[i, j]}
if (j >= W[i]) and (F[i, j] < F[i - 1, j - W[i]] + V[i]) then
F[i, j] := F[i - 1, j - W[i]] + V[i];
end;
end;
procedure Trace; {Truy vết tìm nghiệm tối ưu}
begin
WriteLn(F[n, M]); {In ra giá trị lớn nhất có thể kiếm được}
while n <> 0 do {Truy vết trên bảng phương án từ hàng n lên hàng 0}
begin
if F[n, M] <> F[n - 1, M] then {Nếu có chọn gói thứ n}
begin
Write(n, ' ');
M := M - W[n]; {Đã chọn gói thứ n rồi thì chỉ có thể mang thêm được trọng
lượng M - Wn nữa thôi}
end;
Dec(n);
end;
end;
begin
{Định nghĩa lại thiết bị nhập/xuất chuẩn}
Assign(Input, 'BAG.INP'); Reset(Input);

Assign(Output, 'BAG.OUT'); Rewrite(Output);
Enter;
Optimize;
Trace;
Close(Input); Close(Output);
end.

Cài đặt bài toán cái túi bằng ngôn ngữ C++
#include <iostream>
#include <fstream>
using namespace std;

struct packed
{
int W,V;
};

void GetInput(int &n, int &M, packed *&A)
{
ifstream fi("BAG.INP");
fi>>n>>M;
A=new packed[n+1];
for (int i=1; i<=n; i++)
{
fi>>A[i].W>>A[i].V;
fi.get();
}
fi.close();
}


void Optimize(int n, int M, packed A[],int **&F)
{
F=new int*[n+1];
for (int i=0; i<=n; i++)
F[i] = new int [M+1];
memset(F[0],0,M);
for (int i=1; i<=n; i++)
for (int j=0; j<=M; j++)
{
if (A[i].W<=j && A[i].V+F[i-1][j-A[i].W]>F[i-1][j])
F[i][j]=F[i-1][j-A[i].W] + A[i].V;
else
F[i][j]=F[i-1][j];
}
}

void PutOutput(int **F, packed A[], int n, int M)
{
ofstream fo("BAG.OUT");
fo<<F[n][M]<<endl;
for (;n>0;n )
if (F[n][M] != F[n-1][M])
{
fo<<n<<endl;
M -= A[n].W;
}
fo.close();
}

int main()

{
int n,M;
packed *A;
int **F;
GetInput(n,M,A);
Optimize(n,M,A,F);
PutOutput(F,A,n,M);
delete []A;
for (int i=0;i<=n;i++) delete []F[i];
delete []F;
}

Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Tải bản đầy đủ ngay
×