Thuật toán học trong tin học

11 977 10
Thuật toán học trong tin học

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

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

Thuật toán học trong tin học

ứng dụng lý thuyết Toán để giải các bài TinLê Nguyễn Tuấn Thành(Tiếp theo số trước) Bài 8 Câu 1 Cho một số thập phân vô hạn tuần hoàn dạng A,B(C) với A là phần trước dấu phẩy, B là phần sau dấu phẩy không tuần hoàn, C là phần thập phân tuần hoàn (A,B,C là các số nguyên dương, C<>9). Hãy viết phân số tối giản biểu diễn số thập phân đó. File vào: Thapphan.inp Gồm: 3 số A,B,C ghi trên 3 dòng khác nhau. Nếu B= -1 thì sau dấu phẩy của số đóự chỉ có phần vô hạn tuần hoàn. File ra : Thapphan.out Gồm : Tử và mẫu của phân số tìm được, ghi trên hai dòng Câu 2: Cho phân số có tử và mẫu lần lượt là P,Q (P,Q là các số nguyên dương). Hãy viết dạng biểu diễn thập phân của phân số đó. File vào : Fraction.inp Gồm: P,Q ghi trên cùng một dòng cách nhau bởi dấu cách. File ra: Fraction.out Gồm: Nếu biểu diễn thập phân là vô hạn tuần hoàn thì ghi ra dạng A B C với ý nghĩa như câu 1. Nếu biểu diễn thập phân là hữu hạn thì ghi ra dạng A B. Giải Để giải quyết bài này trước hết tôi nhắc lại 2 định lí quan trọng về phân số được đề cập đến trong SGK lớp 7: Định lí 1: Nếu một phân số tối giản mà mẫu lớn hơn 0 và mẫu không có ước nguyên tố nào khác 2 và 5 thì phân số đó được viết dưới dạng số thập phân hữu hạn. Định lí 2: Nếu một phân số tối giản mà mẫu lớn hơn 0 và mẫu có ước nguyên tố khác 2 và 5 thì phân số đó được viết dưới dạng số thập phân vô hạn tuần hoàn. Bây giờ ta sẽ đi tìm phân số biểu diễn của một số thập phân vô hạn tuần hoàn dạng 0,(c). Gọi k là số chữ số của c Nếu bạn nào tinh ý sẽ để ý thấy rằng số thập phân 0,(9) sẽ không có phân số nào biểu diễn, bởi vì theo trên Điều này không đúng. Trong chương trình tôi viết cho Câu 1 nếu nhập vào 0 −1 9 thì kết quả nhận được là Đây có lẽ là sự thú vị nhất về số thập phân vô hạn tuần hoàn.Định lí 1 và 2 khẳng định mọi phân số đều có thể biểu diễn thành dạng thập phân hữu hạn hoặc vô hạn tuần hoàn, đến đây ta có thể thấy điều ngược lại không đúng. Từ công thức tìm được ở trên, ta có thể dễ dàng giải quyết được Câu 1. Gọi t là số chữ số của B. Như vậy là ta đã tìm được phân số biểu diễn số thập phân vô hạn tuần hoàn A,B(C). Để giải quyết bài toán một cách trọn vẹn thì các bạn phải giải 2 trường hợp B = -1 và B ≠-1. Công thức ở trên mới chỉ giải trường hợp B≠-1. Đối với trường hợp B = -1, bằng cách làm tương tự như trên, ta có được công thức sau: Còn một vấn đề cần giải quyết trước khi viết chương trình đó là: có trường hợp trong dạng biểu diễn của B,C có các chữ số 0 đứng đầu. Như vậy nếu ta đọc B,C từ file với dạng số thì sẽ làm mất đi các chữ số 0 đứng đầu, vì thế sẽ làm sai lệch số chữ số của B,C và khi thay vào công thức tính sẽ cho kết quả sai. Tôi đã giải quyết trường hợp này bằng cách đọc giá trị của B,C vào các xâu, sau đó chuyển xâu sang dạng số để giải. Bằng cách này ta sẽ lưu được số chữ số thực của B,C. Chương trình tôi viết cho hai câu trong bài này chỉ xử lí được các số trong phạm vi longint. Bạn nào muốn xử lí các số lớn hơn phải cài đặt các thuật toán xử lí số lớn. Các thuật toán này đã được giới thiệu trên các số báo trước. Các bạn có thể tham khảo lại để cài đặt. Sau đây là chương trình cho Câu 1: uses crt; const fi='ThapPhan.inp'; fo='ThapPhan.out'; var a,b,c,nb,nc,p,q:longint; xaub:string; xauc:string; {************************************************} procedure nhap; var f:text; z:integer; begin assign(f,fi); reset(f); readln(f,a); readln(f,xaub); readln(f,xauc); close(f); val(xaub,b,z); val(xauc,c,z); end; {************************************************} {Tìm ước chung lớn nhất của hai số nguyên dương a,b} function ucln(a,b:longint):longint; var du:longint; begin ucln:=1; if (a=1) or (b=1) then exit; if a mod b=0 then begin ucln:=b; exit; end; if b mod a=0 then begin ucln:=a; exit; end; while b>0 do begin du:=a mod b; a:=b; b:=du; end; ucln:=a; end; {************************************************} {Tính 10a} function mu10(a:longint):longint; var i,tich:longint; begin tich:=1; for i:=1 to a do tich:=tich*10; mu10:=tich; end; {************************************************} { Cho trường hợp B<>-1} procedure xuli1; begin nb:=length(xaub); nc:=length(xauc); p:=a*mu10(nb)*mu10(nc)-a*mu10(nb)+b*mu10(nc)+c-b; q:=mu10(nb)*(mu10(nc)-1); end; {************************************************} { Cho trường hợp B=-1} procedure xuli2; begin nc:=length(xauc); p:=a*mu10(nc)+c-a; q:=mu10(nc)-1; end; {************************************************} procedure main; var g:text; d:longint; begin nhap; if b=-1 then xuli2 else xuli1; d:=ucln(p,q); p:=p div d; q:=q div d; assign(g,fo); rewrite(g); writeln(g,p); writeln(g,q); close(g); end; {***********************************************} BEGIN clrscr; main; END. Bây giờ chúng ta sẽ giải quyết Câu 2. Trước hết ta thấy rằng theo định lí 1 và 2 dạng biểu diễn của phân số chỉ có thể là hữu hạn hoặc vô hạn tuần hoàn. Là hữu hạn hay vô hạn tuần hoàn phụ thuộc vào Q. Để giải quyết bài toán với các số nhỏ hơn ta đưa phân số về dạng tối giản Ta có thể dễ dàng tìm được giá trị của A : A=P div Q. Lúc đó ta thay P=P mod Q. Từ đây trở đi ta chỉ xét các phân số có tử nhỏ hơn mẫu. Vì vậy chỉ cần đi tìm B và C. Ta sẽ phân tích Q thành dạng: 2t*3k*5n*U (Với t,k,n,U là các số nguyên dương). + Trường hợp 1 Trong phân tích ra thừa số nguyên tố của Q chỉ chứa 2 và 5 mà không chứa bất kì số nguyên tố nào khác, tức là k=0 và U=1 (Q = 2t*5n) Lúc này dạng biểu diễn của sẽ là hữu hạn hay có dạng 0,B. Để tìm được B ta làm như sau: - Nếu t ≤ n ta đưa về dạng Như vậy B=P*2n-t. Gọi nb là số chữ số của B. Như vậy trong biễu diễn dạng số thập phân thì số chữ số 0 đứng liền sau dấu phẩy sẽ bằng: n-nb. - Nếu t >n ta đưa về dạng Như vậy B=P*5t-n. Gọi nb là số chữ số của B. ị Trong biễu diễn dạng số thập phân thì số chữ số 0 đứng liền sau dấu phẩy sẽ bằng: t-nb. +Trường hợp 2: Trong phân tích ra thừa số nguyên tố của Q có chứa các số nguyên tố khác 2 và 5. Q có dạng 2t*3k*5n*U. Như vậy dạng biểu diễn của sẽ là vô hạn tuần hoàn hay có dạng 0,B(C). Theo chứng minh ở trên ta phải đưa về dạng (X là một số nguyên dương và có j chữ số 1 dưới mẫu) Ta sẽ dùng một biến thương để lưu lượng phải nhân thêm vào P và Q để đưa được về dạng , một biến mu10 để lưu số mũ của 10 trong biểu diễn của Q ở trên (cụ thể mu10 =i), một biến sl1 để lưu số chữ số 1 trong biểu diễn của Q (cụ thể sl1 =j) Để đơn giản, ta sẽ loại bỏ khỏi Q phần chứa 2i*5i*9 sau khi nhân thêm với thương. Khi đó Q mới sẽ là ước của 111 11 (j số 1). Cách làm như sau: Khởi tạo thương=1 ; Q:=Q div 2t*3k*5n Lúc đầu thương, mu10 được tính như sau: - Nếu t≤ n thì thương:= thương*2n-t, mu10:=n Ngược lại nếu t > n thì thương :=<i>thương*5t-n, mu10:=t - Nếu k >2 thì Q:=Q*3k-2 Vấn đề còn lại là đi tìm sl1 để 111 11 (có sl1 chữ số1, ta thay j ở trên bằng biến sl1) chia hết cho Q. Theo định lí 2 thì sẽ luôn tìm được sl1. Ta sẽ dùng cách làm tương tự như cách đã làm ở bài 6, nhưng phải chú ý cập nhật thương. Tôi dùng cách làm này để các bạn có thể dễ dàng áp dụng khi cài đặt các thuật toán xử lí số lớn. Thêm hai biến phu và thương10 có ý nghĩa sau: phu để lưu thương của 111 11 khi chia cho Q thương10 để lưu thương của 10sl1 khi chia cho Q, thương10 sẽ được cập nhật liên tục khi sl1 tăng lên. Thủ tục tìm sl1 sẽ như sau: Chú ý: k trong thủ tục thay cho Q. Procedure so_luong_so_1(k:longint); var du,du10,thuong10,phu:longint; begin sl1:=1; if k=1 then exit; phu:=0; du:=1; du10:=1; thuong10:=0; repeat inc(sl1); thuong10:=thuong10*10+du10*10 div k; du10:=du10*10 mod k; phu:=phưthuong10+(dưdu10) div k; du:= (dưdu10) mod k; until du=0; thuong:=thuong*phu; end; Biến du sẽ lưu số dư của 111 11 khi chia cho Q. Biến thương sẽ được tính lại là: thuong:=thuong*phu Chương trình bị hạn chế bởi thương, thương10, phu là dạng longint nên chỉ chạy được với Q khá nhỏ. Các bạn có thể bỏ các dòng lệnh chứa thương,thương10, phu để có thể tìm sl1 với Q lớn hơn. Còn một lưu ý nữa là: khi mu10 = 0 thì B = -1, do đó phải xử lý thêm trường hợp này. Sau khi tìm được thương thì P:=P*thương. Để viết được dạng biểu diễn thập phân, chúng ta phải tìm được B và C. Ta thấy rằng nếu không tính các chữ số 0 đứng đầu thì số chữ số của B Ê mu10, số chữ số của C ≤ sl1. Theo trên P sẽ có dạng: B*(10sl1-1)+C. Từ đó ta sẽ duyệt toàn bộ các giá trị có thể có của B và C (với chú ý điều kiện về số chữ số của B,C). Sau khi tìm được B,C cách tính số chữ số 0 đứng đầu trong B,C các bạn có thể làm theo cách đã giới thiệu ở trong trường hợp 1. Sau đây là chương trình cho câu 2: uses crt; const fi='Fraction.inp'; fo='Fraction.out'; var p,q,a,b,c,thuong:longint; mu2,mu3,mu5,mu10,sl1:word; f:text; {************************************************} procedure nhap; begin assign(f,fi); reset(f); readln(f,p,q); close(f); assign(f,fo); rewrite(f); end; {************************************************} {Tìm số mũ của số nguyên tố a trong dạng phân tích ra thừa số nguyên tố của So} function mu(a:word;var so:longint):word; var k:word; begin k:=0; while so mod a=0 do begin inc(k); so:=so div a; end; mu:=k; end; {************************************************} {Tìm ước chung lớn nhất của hai số nguyên dương a,b} function ucln(a,b:longint):longint; var du:longint; begin ucln:=1; if (a=1) or (b=1) then exit; if a mod b=0 then begin ucln:=b; exit; end; if b mod a=0 then begin ucln:=a; exit; end; while b>0 do begin du:=a mod b; a:=b; b:=du; end; ucln:=a; end; {************************************************} {Tinh as } function mu_as(a,s:word):longint; var i,tich:longint; begin tich:=1; for i:=1 to s do tich:=tich*a; mu_as:=tich; end; {************************************************} {Tìm số chữ số cảu một số nguyên dương a} function scs(a:longint):longint; var k:longint; begin if a=0 then begin scs:=1; exit; end; k:=0; while a>0 do begin a:=a div 10; inc(k); end; scs:=k; end; {************************************************} procedure huu_han; var so,i:word; begin p:=p*thuong; so:=scs(p); if mu2>=mu5 then begin for i:=1 to mu2-so do write(f,0); write(f,p); end else begin for i:=1 to mu5-so do write(f,0); write(f,p); end; close(f); halt; end; {***********************************************} procedure so_luong_so_1(k:longint); var du,du10,thuong10,phu:longint; begin sl1:=1; if k=1 then exit; phu:=0; du:=1; du10:=1; thuong10:=0; repeat inc(sl1); thuong10:=thuong10*10+du10*10 div k; du10:=du10*10 mod k; phu:=phưthuong10+(dưdu10) div k; du:=(dưdu10) mod k; until du=0; thuong:=thuong*phu; end; {***********************************************} procedure vo_han_tuan_hoan; var phu,lim:longint; begin so_luong_so_1(q); p:=p*thuong; if mu10=0 then begin write(f,-1,' '); for phu:=1 to sl1-scs(p) do write(f,0); write(f,p); close(f); halt; end; phu:=mu_as(10,sl1)-1; lim:=p div phu; for b:=0 to lim do if scs(b)<=mu10 then begin c:=p-b*phu; if scs(c)<=sl1 then break; end; for phu:=1 to mu10-scs(b) do write(f,0); write(f,b,' '); for phu:=1 to sl1-scs(c) do write(f,0); write(f,c); close(f); end; {************************************************} procedure xuli; var d:longint; begin d:=ucln(p,q); p:=p div d; q:=q div d; a:=p div q; p:=p mod q; write(f,a,' '); mu2:= mu(2,q); mu3:= mu(3,q); mu5:= mu(5,q); thuong:=1; if mu2>=mu5 then begin thuong:=thuong*mu_as(5,mu2-mu5); mu10:=mu2; end else begin thuong:=thuong*mu_as(2,mu5-mu2); mu10:=mu5; end; if (mu3=0) and (q=1) then huu_han; if mu3<2 then thuong:=thuong*mu_as(3,2-mu3) else if mu3>2 then q:=q*mu_as(3,mu3-2); vo_han_tuan_hoan; end; [...]... xâu, sau đó chuyển xâu sang dạng số để giải. Bằng cách này ta sẽ lưu được số chữ số thực của B,C. Chương trình tơi viết cho hai câu trong bài này chỉ xử lí được các số trong phạm vi longint. Bạn nào muốn xử lí các số lớn hơn phải cài đặt các thuật tốn xử lí số lớn. Các thuật tốn này đã được giới thiệu trên các số báo trước. Các bạn có thể tham khảo lại để cài đặt. Sau đây là chương trình cho Câu... hồn phụ thuộc vào Q. Để giải quyết bài toán với các số nhỏ hơn ta đưa phân số về dạng tối giản Ta có thể dễ dàng tìm được giá trị của A : A=P div Q. Lúc đó ta thay P=P mod Q. Từ đây trở đi ta chỉ xét các phân số có tử nhỏ hơn mẫu. Vì vậy chỉ cần đi tìm B và C. Ta sẽ phân tích Q thành dạng: 2 t *3 k *5 n *U (Với t,k,n,U là các số nguyên dương). + Trường hợp 1 Trong phân tích ra thừa số nguyên tố... trên mới chỉ giải trường hợp B≠-1. Đối với trường hợp B = -1, bằng cách làm tương tự như trên, ta có được cơng thức sau: Còn một vấn đề cần giải quyết trước khi viết chương trình đó là: có trường hợp trong dạng biểu diễn của B,C có các chữ số 0 đứng đầu. Như vậy nếu ta đọc B,C từ file với dạng số thì sẽ làm mất đi các chữ số 0 đứng đầu, vì thế sẽ làm sai lệch số chữ số của B,C và khi thay vào công... k=0 và U=1 (Q = 2 t *5 n ) Lúc này dạng biểu diễn của sẽ là hữu hạn hay có dạng 0,B. Để tìm được B ta làm như sau: - Nếu t ≤ n ta đưa về dạng Như vậy B=P*2 n-t . Gọi nb là số chữ số của B. Như vậy trong biễu diễn dạng số thập phân thì số chữ số 0 đứng liền sau dấu phẩy sẽ bằng: Như vậy là ta đã tìm được phân số biểu diễn số thập phân vơ hạn tuần hồn A,B(C). Để giải quyết bài tốn một cách trọn . câu trong bài này chỉ xử lí được các số trong phạm vi longint. Bạn nào muốn xử lí các số lớn hơn phải cài đặt các thuật toán xử lí số lớn. Các thuật toán. của c Nếu bạn nào tinh ý sẽ để ý thấy rằng số thập phân 0,(9) sẽ không có phân số nào biểu diễn, bởi vì theo trên Điều này không đúng. Trong chương trình

Ngày đăng: 11/09/2012, 15:00

Từ khóa liên quan

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

Tài liệu liên quan