Mơ hình thuật tốn tham lam

Một phần của tài liệu (LUẬN văn THẠC sĩ) thuật toán xấp xỉ ứng dụng vào một số bài toán lớp NP (Trang 29 - 34)

Hình 1 .1 Bài tốn xếp ba lô dạng 0-1

2.3 Phương pháp tham lam

2.3.5 Mơ hình thuật tốn tham lam

Ta xây dựng tập S dần từng bước, bắt đầu từ tập rỗng. Tại mỗi bước ta sẽ chọn một phần tử “tốt nhất” trong các phần tử còn lại của A để đưa vào S. Việc lựa chọn một phần tử như thế ở mỗi bước được hướng dẫn bởi hàm chọn. Phần tử được chọn sẽ bị loại khỏi tập A. Nếu khi thêm phần tử được chọn vào tập S mà S vẫn còn thỏa mãn các điều kiện của bài tốn thì ta mở rộng S bằng cách thêm vào phần thử được chọn.

Thuật toán tham lam tổng quát được mô tả như sau

Mô hình:

Chọn S từ tập A;

Tính chất tham lam của thuật toán được định hướng bởi hàm Select() - Khởi động S = 

- Trong khi A ≠ :

+ Chọn phần tử tốt nhất của A gán vào x: x Select(A) + Cập nhật các đối tượng để chọn A: A = A –{x}

+ Nếu S  {x} thỏa mãn yêu cầu bài tốn thì: Cập nhật lời giải S = S  {x}

Thuật tốn tham lam được mơ tả bằng thủ tục sau

Procedure Greedy(A, S) // A là một tập các ứng cử viên, X là tập quyết định –

nghiệm

+ Input A// Tập các đối tượng cho trước

+ Output X //Lời giải, xây dựng phương án X từ A Begin

X  ;

Begin

x  Select(A); AA-{x};

if X  {x} được thừa nhận then XX {x}; end;

end;

Trong thủ tục trên tổng quát trên, Select là hàm chọn, cho phép chọn từ tập A một phần tử được xem là tốt nhất, nhiều hứa hẹn nhất là thành viên của tập nghiệm X.

Sau đây chúng ta sẽ xem xét một số ví dụ thiết kế thuật tốn tham lam

Ví dụ 2.2: Xét lại Bài toán KNAPSACK

Input: + Cho n đồ vật, đồ vật thứ i có thể tích là wi, có giá trị là pi + Cho 1 ba lơ có thể tích M

Output: Hãy xác định nhóm đồ vật thỏa mãn: tổng thể tích khơng vượt q ba lô đồng thời tổng giá trị là lớn nhất

Phân tích:

Hiển nhiên theo tư tưởng tự nhiên thì để lấy đồ vật có lợi nhất, chúng ta cần thực hiện chiến lược lấy đồ vật có giá trị cao nhất với thể tích nhỏ nhất tại thời điểm hiện tại cho đến khi khơng thể lấy được nữa thì dừng. Vì vậy ta xây dựng thuật tốn theo tư tưởng tham lam như sau:

Bước 1: Sắp xếp các đồ vật theo thứ tự giảm dần của tỉ số

w

i

i

p

(i=1,2,…,n)

Bước 2: Khởi động tập hợp S = Ỉ Là tập các đồ vật cần lấy.

Bước 3: Kết nạp lần lượt các đồ vật theo thứ tự sắp xếp vào S, mỗi lần kết nạp cần

kiểm tra thể tích của S phải khơng vượt q M.

Thuật toán được mơ tả bằng ngơn ngữ lập trình C++ như sau: #include <Windows.h>

#define N 100

using namespace std; void swap(int &a,int &b) { int tg;

tg=a;a=b;b=tg;}

void input(int W[],int P[],int &M,int &n) { cout<<"Nhap so do vat: ";cin>>n;

cout<<"Nhap the tich ba lo: ";cin>>M;

cout<<"Nhap the tich cac do vat: ";printf("\n");

for (int i=1;i<=n;i++) {cout<<"Do vat: "<<i<<" ";cin>>W[i];} cout<<"Nhap gia tri cac do vat : ";printf("\n");

for (int i=1;i<=n;i++) {cout<<"Do vat: "<<i<<" ";cin>>P[i];} }

void output(int W[],int X[],int n)

{ cout<<"Cac do vat sau khi sap xep theo gia tri giam dan: ";printf("\n"); for (int i=1;i<=n;i++) cout<<X[i]<<" ";printf("\n");

for (int i=1;i<=n;i++) cout<<W[i]<<" ";printf("\n"); }

void bubble_sort(int W[],int X[],int P[],int n) { int i,j;int C[n];

for (i=1;i<=n;i++) C[i]=P[i]/W[i]; for (i=n;i>1;i--) { for (j=2;j<=i;j++) if (C[j-1]<C[j]) {swap(C[j-1],C[j]);swap(W[j-1],W[j]);swap(X[j-1],X[j]);swap(P[j-1],P[j]);} }} int main() { int i,n,T,M; int W[N],X[N],P[N]; input(W,P,M,n);

for (i=1;i<=n;i++) X[i]=i; bubble_sort(W,X,P,n);

cout<<"Phuong an lay trom: Hay lay cac do vat: "; printf("\n");

i=1;T=0; while (i<=n)

{ if (M-W[i]>0){cout<<X[i]<<" ";M=M-W[i];T=T+P[i];} i=i+1;}

printf("\n");

cout<<"Tong gia tri: "<<T; }

Ví dụ 2.3: Bài tốn đổi tiền

Input:

+ Có n loại tiền với các mệnh giá mi, số lượng các mệnh giá là không hạn chế.

+ Có số tiền thừa là b Output:

Phương án trả tiền thừa cho khách hàng sao cho tổng số tờ là ít nhất.

Phân tích:

Hiển nhiên theo tư tưởng tự nhiên thì để số tờ là ít nhất, chúng ta cần thực hiện chiến lược trả loại tiền có mệnh giá cao nhất tại thời điểm hiện tại, sau đó chọn tiếp các mệnh giá thấp hơn để trả cho đến khi trả hết số tiền thừa.

Vì vậy ta xây dựng thuật tốn theo tư tưởng tham lam như sau

Bước 1: Sắp xếp các tờ mệnh giá theo giá trị mệnh giá giảm dần

Bước 2: Khởi động S=0 (S chứa giá trị tiền đã trả)

Bước 3: Lần lượt trả các tờ tiền mệnh giá lớn nhất (Tại thời điểm hiện tại), mỗi lần

trả cần kiểm tra S-b>0 tức là việc trả là hợp lệ. Nếu khơng hợp lệ thì chọn tờ tiền có mệnh giá tiếp sau.

Q trình sẽ kết thúc khi S-b=0.

Thuật tốn được mơ tả bằng ngơn ngữ lập trình C++ như sau: #include <Windows.h>

#define N 100

using namespace std; void swap(int &a,int &b) { int tg;

tg=a;a=b;b=tg;}

{ cout<<"Don vi quy uoc la ngan dong: ";printf("\n"); cout<<"Nhap so menh gia: ";cin>>n;

cout<<"Nhap so tien thua: ";cin>>T;

cout<<"Nhap menh gia cac dong tien: ";printf("\n");

for (int i=1;i<=n;i++) {cout<<"Loai tien thu: "<<i<<" ";cin>>A[i];} }

void output(int A[],int X[],int n)

{ cout<<"Cac menh gia sau khi sap xep theo gia tri giam dan: ";printf("\n"); for (int i=1;i<=n;i++) cout<<X[i]<<" ";printf("\n");

for (int i=1;i<=n;i++) cout<<A[i]<<" ";printf("\n"); }

void bubble_sort(int A[],int X[],int n) {int i,j;int C[n]; for (i=n;i>1;i--) { for (j=2;j<=i;j++) if (A[j-1]<A[j]) {swap(A[j-1],A[j]);swap(X[j-1],X[j]);} }} int main() { int i,n,T,k; int A[N],X[N]; input(A,T,n);

for (i=1;i<=n;i++) X[i]=i; bubble_sort(A,X,n);

cout<<"Phuong an tra tien thua: Hay tra cac loai menh gia: "; printf("\n");

for (i=1;i<=n;i++) { k=T/A[i];

if (k>0) {T=T-k*A[i];cout<<"Menh gia"<< A[i]<<" So to tien :"<<k;} else

cout<<"Menh gia: "<< A[i]<<" So to tien :"<<0; printf("\n");}

cout<<"So du: "<<T; }

Nhận xét: Qua 2 ví dụ trên chúng ta có thể thấy

+ Thuật tốn tham lam được thiết kế rất đơn giản, dễ hiểu

+ Thuật toán thường sử dụng phương án sắp xếp do đó có độ phức tạp thuật toán là thấp (Nếu dùng sắp xếp đệ quy thì độ phức tạp là O(nlogn)).

+ Về cơ bản nghiệm thu được chỉ là nghiệm xấp xỉ. Để tìm nghiệm chính xác chỉ có thể nhận được bằng thuật toán quay lui.

+ Điểm mấu chốt của thuật tốn chính là việc xác định được cơ chế chọn Select()

Một phần của tài liệu (LUẬN văn THẠC sĩ) thuật toán xấp xỉ ứng dụng vào một số bài toán lớp NP (Trang 29 - 34)

Tải bản đầy đủ (PDF)

(72 trang)