1. Trang chủ
  2. » Công Nghệ Thông Tin

Các bài toán quen thuộc trong lập trình Pascal

5 3,3K 58
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 5
Dung lượng 69 KB

Nội dung

Các bài toán quen thuộc trong lập trình Pascal

Trang 1

Cách nhìn khác đối với một số lớp bài toán quen thuộc

Cao Minh Anh

Các bạn đã bao giờ thích thú khi tìm ra một cách nhìn nhận mới cho những bài mình đã biết? Thật là thú vị nếu ta tìm cho mình một phương pháp khác mà tính tối ưu vẫn không giảm

Sau đây tôi sẽ trình bày với các bạn một cách nhìn nhận khác đối với lớp bài toán như xác định hoán vị thứ k, nhị phân thứ k, …

Tư tưởng thuật toán

- Giả sử cần tìm 1 trạng thái nào đó gồm n phần tử của một dạng xác định Đề bài cho biết đặc điểm của trạng thái trên là M

- Với M ta có thể xác định phần tử đầu tiên của trạng thái, nhưng n-1 phần tử còn lại thì không xác định được Vấn đề bây giờ là làm sao tìm được n-1 trạng thái còn lại Rất đơn giản, bởi vì nếu biết được M ta sẽ xác định được phần tử đầu tiên, tại sao ta không thử n-1 phần tử còn lại có phải thuộc một trạng thái nào đó gồm n-1 phần tử có đặc điểm M1 Từ M1 này ta suy được phần tử đầu tiên của trạng thái mới, tức là đã tìm được phần tử thứ 2 của trạng thái ban đầu Cứ làm như thế ta sẽ tìm được hết các phần tử của trạng thái ban đầu

- Cái khó của thuật toán trên là đòi hỏi người lập trình phải tìm được cách xác định phần tử đầu tiên dựa vào đặc điểm M, thứ hai là phải tìm được các đặc điểm M1, M2, , Mn-1 tương ứng với các trạng thái mới có ít phần tử hơn

Bài toán 1

Xác định dãy nhị phân thứ k gồm n phần tử (n≤200)

File nhiphan.inp

n k

File nhiphan.out

a1 a2 a3 an (dãy nhị phân thứ k)

Ví dụ

nhiphan.inp

4 7

nhiphan.out

0 1 1 0

Thuật toán

Trang 2

Dựa vào ví dụ dưới ta nhận thấy rằng:

- Có 1 nửa trạng thái đầu tiên có số 0 đứng đầu, còn nửa còn lại là số 1 đứng đầu Hay có

2n-1 trạng thái đầu tiên bắt đầu là số 0, còn lại 2n-1 trạng thái bắt đầu là số 1 Như vậy chỉ cần so sánh k với 2n-1 thì ta có thể biết được phần tử đầu tiên của dãy nhị phân thứ k là 0 hay 1

If k>2n-1 then a[1]=1 else a[1]=0

- Vấn đề còn lại là làm sao xác định được n-1 phần tử còn lại

- Ta nhận thấy rằng nếu phần tử đầu tiên là 0 thì n-1 phần tử còn lại giống với các phần tử của dãy nhị phân thứ k có n-1 phần tử, còn nếu phần tử đầu tiên là 1 thì n-1 phần tử còn lại giống với các phần tử của dãy nhị phân thứ (k-2n-1) có n-1 phần tử Bây giờ ta lại làm bài toán nhỏ hơn là xác định dãy nhị phân thứ k’ nào đó gồm n-1 phần tử Cứ làm như thế ta sẽ tìm được hết các phần còn lại

Từ những nhận xét trên ta có chương trình đơn giản như sau:

For I:=n downto 1 do

Begin

If k>1 shl (I-1) then

Begin

Write(‘1’);

K:=k-(1 shl (I-1));

End

Else write(‘0’);

End;

Vì bài này dữ liệu lớn, ta chỉ cần làm thêm chương trình nhân số lớn để tính 2h, và hàm so sánh 2 xâu k với 2h

Bài 2

Trang 3

Tìm hoán vị thứ k gồm n phần tử (n≤200)

Thuật toán

Nhận xét

- (n-1)! Trạng thái đầu tiên có phần tử đầu tiên là 1, tiếp theo (n-1)! Tiếp là 2, tiếp tới là 3,

và cuối cùng là 4

- Dựa vào k ta có thể xác định phần tử đầu tiên Nếu tìm được phần tử đầu tiên là h thì dùng mảng b để đánh dấu h, để n-1 phần tử còn lại không có h

- Bây giờ cần xác định vị trí k’ của n-1 phần tử còn lại

- K’ = k-v (với v là vị trí đầu tiên bắt đầu bằng số h) Việc tính v rất dễ dàng

Đây là phần giải tạm với dữ liệu k≤232

Fillchar(b,sizeof(b),1);

T:=1;

For I:=1 to n do T:=T*I;

For I:=n downto 1

Begin

T:=T div I;

For j:=1 to n do

If b[j] then

Begin

if K>T then k:=k-T

else

begin

write(j:4);

Trang 4

b[j]:=false;

break;

end;

end;

end;

Ta có thể nâng dữ liệu lên n≤1000, chỉ cần làm chương trình nhân số lớn và hàm so sánh hai số lớn là xong

Bài 3

(Đề 2 - dãy nhị phân olympic tin học sinh viên khối chuyên tin)

Xét tập S các dãy nhị phân độ dài N trong đó không có hai bit 1 nào kề nhau Các dãy này được xếp theo chiều tăng dần của số nguyên mà nó biểu diễn, theo thứ tự đó mỗi dãy có một số hiệu, chẳng hạn n=5

Cho số nguyên dương N≤100 hãy nhị phân có số hiệu M

Ví dụ

BINSEQ.inp

5 5

BINSEQ.out

0 0 1 0 1

Thuật toán

Đây là một bài rất khó để ta xác định cách xác định phần tử đầu tiên

Trang 5

Nhận xét :

Với n=5 có 13 dãy tất cả Trong đó có 8 dãy đầu tiên bắt đầu bằng 0,5 dãy còn lại bắt đầu bằng 1 Với n=6 thì có tất cả 21 dãy, 13 cái đầu là 0,8 cái sau là 1 Ta thấy nó có liên quan đến số fibonaci

Chỉ cần kiểm tra M với a[n-1], nếu M>a[n-1] thì đó là số 0 đầu tiên, ngược lại là số 1 đầu tiên Nếu số đầu tiên là 0 thì trạng thái mới cần tìm gồm n-1 phần tử có số hiệu vẫn là M, ngược lại có số hiệu là M-a[n-1]

Bài làm rất đơn giản như sau:

a[0]:=1;a[1]:=1;

For I:=2 to n do a[I]:=a[I-1]+a[I-2];(Tạo các số fibo)

For I:=n downto 1 do

Begin

If M>a[I-1] then

Begin

Write(‘1’);

M:=M-a[I-1];

End

Else write(‘0’);

End;

Thật là đơn giản phải không các bạn? Vấn đề ở chỗ phải tìm ra đặc điểm để xác định phần

tử đầu tiên và đặc điểm của các phần tử còn lại Hi vọng các bạn sẽ nhận thêm được kinh nghiệm nào đó từ bài viết này

Ngày đăng: 07/09/2012, 11:12

TỪ KHÓA LIÊN QUAN

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN

w