Tải bản đầy đủ (.doc) (9 trang)

BÀI TẬP LỚN VỀ THUẬT TOÁN

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 (138.53 KB, 9 trang )

BÀI BÁO CÁO THUẬT TOÁN
Đề bài: Giả sử ổ khóa có n công tắc. Mỗi công tắc có một trong 2 trạng thái “đóng” hay
“mở”. Khóa mở được nếu có ít nhất [n/2] công tắc ở trạng thái “mở”. Liệt kê tất cả các
cách mở khóa.
BÀI LÀM:
1. Tóm Tắt Đề Bài:
• Input:
 n công tắt.
 Mỗi công tắt có 2 trạng thái “đóng” hay “mở”.
 Khóa mở nếu có ít nhất [n/2] công tắt “mở”.
• Output:
 Liệt kê tất cả các cách mở khóa.
2. Ý Tưởng:
• Theo giả thiết bài cho, ta có:
Mỗi công tắt có 2 trạng thái “đóng” hay “mở”.
=> tỉ lệ trạng thái “đóng” và trạng thái “mở” ở đây là bằng nhau.
• Mặt khác, cũng theo giả thiết bài cho:
Khóa được mở nếu có ít nhất [n/2] công tắt ở trạng thái mở. Nghĩa là khi
có [n/2], [n/2+1], [n/2+2],…, [n-1], [n] công tắt ở trạng thái “mở” thì khóa
sẽ được mở.
=> Cách giải quyết bài toán là đi liệt kê tất cả các tập con có k phần tử của tập n
phần tử của các tổ hợp Cnk (với k = n/2, n/2+1,…, n-1, n).
VD: Với n=5 ta liệt ra được 16 cách mở được khóa như:
(123), (124), (125), (134), (135), (145), (234), (235), (245), (345), (1234),
(1235), (1245), (1345), (2345), (12345).
VD: Với n= 4 ta liệt kê được 11 cách mở khóa:
(12), (13), (14), (23), (24), (34), (123), (124), (134), (234), (1234).
• Liệt kê tất cả các tập con có k phần tử của tập n phần tử tổ hợp Cnk (với k chạy
từ n/2, n/2+1, n/2+2, n-1,n).

1




Liệt kê tập con có k phần tử từ tập n có sẵn ta sử dụng phương pháp sinh kế
tiếp từ tập con c1, c2, c3,..., ck phần tử có trước:
Bước 1: Cho j chạy tìm từ vị trí đầu tiên từ bên trái sang 1 vị trí c[i] nào
đó sao cho c[i]<= n.
Gán c[i]:= j;
Bước 2: Thực hiện kiểm tra xem nếu mà vị trí i còn bé hơn giá trị k
không?
o Nếu điều kiện trên đúng thì quay lại bước 1 với vị trí i tăng
thêm 1.
o Nếu điều kiện trên không đúng thì thoát khỏi vòng lặp và in
kết quả tất cả các tập con có k phần tử.
 Nhận xét ở bước 2 có thực hiện thử điều kiện nếu sai thì thực hiện việc in
kết quả, ngược lại thì thực hiện quay lại công việc trước đó để làm.
3. Giả mã bài toán:
procedure InKQ (k:integer) ; // thủ tục in ra kết quả theo đề cho.
Begin
i, d: integer; //biến nguyên i dùng làm biến chạy, d là một biến đếm số cách bật
đèn.
d= d+1;
//in ra cách bật đèn thứ d.
for i:=1 to k do //k là số đèn bật.

(1)

in ra giá trị c[i]; //c[i] là mảng dùng để lưu cách bật đèn.
i:=i+1;

(2)


End;
procedure tohop (i: integer, k: integer, n: integer); //thủ tục liệt kê tập con k phần tử
của tập n phần tử.
Begin
j: integer; //biến chạy trên mảng c.
for j:=[i-1]+1 to n do

(3)
2


begin
c[i]:=j;

(4)

if (itohop(i+1,k,n)
else
InKQ(k);

(5)
(6)
(7)

end;
End;
procedure thongbao (n: integer); //thủ tục đưa ra thông báo tất cả các cách mở khóa.
Begin

t, k, i: integer;
t:=n/2; // t khởi tạo và cố định số đèn ở trạng thái bật ít nhất để đảm bảo có thể
mở được khóa.

(8)

k:=t;

(9)

If (n lẻ) then tăng t thêm 1;

(10)

For k to n do

(11)

begin
for i:=1 to k do

(12)

c[i]:=j;

(13)

tohop(1,k,n);

(14)


i:=i+1;

(15)

end;
k:=k+1;// tăng số phần tử trong tập con lên 1 để tính và liệt kê tất cả các tập
con có k phần tử.

(16)

End;
4. Đánh giá độ phức tạp thuật toán:
 Để tính độ phức tạp của thuật toán:
 Câu lệnh (2) mất thời gian thực hiện là: O(1).
 Câu lệnh (1) lặp từ 1 đến k (k=n/2) => thời gian thực hiện là: O(n/2)*1=O(n).
3


 Câu lệnh (4) mất thời gian thực hiện là: O(1).
 Câu lệnh (5) thực hiện phép so sánh mất thời gian O(1).
 Câu lệnh (6), (7) thực hiện câu lệnh if mất thời gian O(1).
 Câu lệnh (3) có thời gian thực hiện là: O(n).
=> Tổng thời gian thực hiện là: O(n).
 Câu lệnh (16), (15), (13), (14), (10), (9), (8) mất thời gian thực hiện là: O(1).
 Câu lệnh (12) biến i chạy từ 1 đến k là: O(n).
 Câu lệnh (11) thực hiện lặp từ k đến n là: O(n).
=> vậy thời gian thực hiện là: O(n2).
Vậy thời gian thục hiện chương trình là: O(n2).
5. Mã hóa bằng ngôn ngữ C:

#include<conio.h>
#include<stdio.h>
int d;
int c[100];
void inKQ(int k)
{
int i;
d++;
printf("\n cach thu %3d:bat den",d);
for(i=1;i<=k;i++)
printf("%4d",c[i]);
}
void tohop(int i,int k,int n)
{
int j;
for(j=c[i-1]+1;j<=n;j++)
{
c[i]=j;
if(i4


tohop(i+1,k,n);
else
inKQ(k);
}
}
void thongbao(int n)
{


int t=n/2;
int k,i;
if (n%2==1) t++;
for(k=t;k<=n;k++)
{
for(i=1;i<=k;i++) c[i]=i;
tohop(1,k,n);
}
printf ("\nTong cac cach bat den:%d",d);

}
void main()
{
clrscr();
thongbao(5);
getch();
}
6. Ví dụ minh họa:
n=2
t=1
k=1
i=1

c[1]=1
tohop(1,1,2)

j=1

5


c[1]=1 => In 1


j=2

c[1]=2 => In 2

j=1

c[1]=1
tohop(2,2,2)

k=2
i=1

c[1]=1
tohop(1,2,2)

j=2
c[2]=2

j=2
không thực hiện (vì i>k).
=> c[i]= (1 2).

n=2 kết quả chạy chương trình :

n=3 kết quả chạy chương trình:

n=4 kết quả chạy chương trình:

6


n=5 kết quả chạy chương trình:

7


n=
10 kết quả chạy chương trình:

8


9



×