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

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

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

Thông tin tài liệu

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

Cách nhìn khác đối với một số lớp bài toán quen thuộcCao Minh AnhCá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 7nhiphan.out 0 1 1 0 Thuật toán 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 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); 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 5BINSEQ.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. 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. . Cách nhìn khác đối với một số lớp bài toán quen thuộcCao Minh AnhCá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. đâ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ử

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

Từ khóa liên quan

Tài liệu cùng người dùng

  • Đang cập nhật ...

Tài liệu liên quan