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

Bài toán số nguyên tố tối ưu

8 1,2K 12
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 8
Dung lượng 62,5 KB

Nội dung

Bài toán số nguyên tố tối ưu

Trang 1

Tối ưu các bài toán về số nguyên tố

Đinh Hữu Công

Trong số 11-2001 tácgiả Nguyễn Văn Trường đã giới thiệu các thuật toán về số nguyên tố.Nhưng một số thuật toán này còn bị hạn chế về thời gian và bộ nhớvới n lớn Tuỳ vào từng bài toán cụ thể ta có thể tối ưu hoá nhữngthuật toán này dựa vào những nhận xét và chứng minh toán học

Bài toán 1: Cho số tựnhiên n Hãy phân tích số n thành tích các thừa số nguyên tố

Input: file Phantich.inp với số n duy nhất (n < 231)

Ouput: file Phantich.out Dòng 1 là k, số thừa số nguyên tố khác nhautrong phân tích K

dòng tiếp theo dòng thứ i gồm 1 cặp số (p,q) cáchnhau 1 dấu trắng trong đó p là thừa số nguyên tố và q là số mũ tươngứng của nó trong phân tích (q > 0)

Thuật toán của bài này rất đơn giản:

+ Cho biến chạy Temp=0,

+ Lặp: Chừng nào temp≤n thì làm

- Temp:=số nguyên tố liền sau Temp;

- While (n mod Temp=0) do

Begin

n:=n div Temp;

Tăng số mũ của Temp;

End;

Hiệuquả của cài đặt chủ yếu phụ thuộc vào công đoạn tìm số nguyên tốliền sau Temp Cách nhanh nhất là dùng 1 mảng để lưu trữ các số nguyêntố từ 1 đến n Với n=1 tỷ ta phải lưu (109) = 50.847.534 số nguyên tố nên ta không thể có đủ bộnhớ để thực hiện điều này Một cách khác là ta tuần tự tăng biếnTemp và kiểm tra Temp có nguyên tố không, cách này không tốn bộ nhớnhưng không khả thi vì thời gian thực hiện quá lâu Một cách tự nhiên,ta muốn dung hoà cả hai phương pháp trên Vì vậy ta sẽ tìm cách giảmkhối lượng lưu trữ và số lần kiểm tra nguyên tố:

Bước 1: Kiểm tra n Nếu n nguyên tố hoặc n=1thìvấn đề trở nên quá đơn giản Nếu n là

hợp số thì chuyển sang bước2

Bước 2: Vì n là hợp số nên ta phải có n=a*b(1<a ≤ b) suy ra a ≤ sqrt(n)≤ 215,5 < 1 Vậy ta chỉ cần lưu các số nguyên tố nhỏ hơn 6341

Vìn< 231 nên số thừa số nguyên tố nhỏ hơn 10 (2*3*5* 31 >231), do đó ta chỉ phải kiểm tra nguyên tố khoảng 10 lần

Chươngtrình của bài này như sau:

{$A+,B-,D+,E+,F-,G-,I+,L+,N-,O-,P-,Q+,R+,S+,T-,V+,X+}

{$M65500,0,655360}

{Phantich so n<2^31 thanh thua so nguyen to}

usescrt;

Fin=′phantich.inp′;

Fou=′phantich.out′;

var p:array[1 10] of longint;

Trang 2

q:array[1 10] of integer; { Số thừa số nguyên tố lớn nhất là 10?} Prime:array[0 maxPrime+1] of boolean;

n:longint;

count:integer;

temp:word;

f,g:text;

procedureEratosten;

vari,j:word;

begin

Fillchar(Prime,sizeof(Prime),true);

Prime[0]:=false;

Prime[1]:=false;

for i:=2 to trunc(sqrt(maxPrime)) do

if Prime[i] then

for j:=2 to (maxPrime div i) do

Prime[i*j]:=false;

end;

functionisPrime(n:longint):boolean;

vari,step:word;

begin

isPrime:=false;

if (n

begin

if Prime[n] then isPrime:=true;

exit;

end;

if ((n mod 2=0) or (n mod 3=0)) then Exit;

i:=5;

step:=2;

while (i≤sqrt(n)) do

begin

if (n mod i=0) then

exit;

i:=i+step;

step:=6-step;

end;

isPrime:=true;

end;

procedureSolve;

begin

Assign(f,Fin);

Reset(f);

Readln(f,n);

Close(f);

Assign(g,Fou);

Rewrite(g);

Trang 3

if n<2 then

begin

writeln(g,0);

Close(g);

Halt;

end;

temp:=2;

count:=0;

Fillchar(p,sizeof(p),0);

Fillchar(q,sizeof(q),0);

while (n<>1) do

begin

if isPrime(n) then

begin

Inc(count);

p[count]:=n;

q[count]:=1;

exit;

end

else

begin

while ((n mod temp<>0) and (temp< i> begin

Inc(temp);

while not Prime[temp] do

Inc(temp);

end;

Inc(count);

p[count]:=temp;

while (n mod temp=0) do

begin

Inc(q[count]);

n:=n div temp;

end;

end;

end;

end;

procedureResult;

vari:integer;

begin

Writeln(g,count);

for i:=1 to count do

Writeln(g,p[i],' ',q[i]);

Close(g);

end;

BEGIN

Trang 4

Eratosten;

Solve;

Result;

END

Saukhi làm bài toán 1 ta sẽ dễ dàng làm được bài toán số 2 trong đềkhối 10 cuộc thi Olympic 30-4 lần VIII

Đề bài như sau:

Cho số nguyên dương n (1 < n < 231) Tìm số nguyêndương a nhỏ nhất sao cho a a chia hết cho n

Input: file Chiahet.inpchứa 1 số duy nhất n

Output: file Chiahet.out chứa số a

Bàitoán 2: Tìm số mũ của số nguyên tố p trong cách phân tích của n! ra thừa sốnguyên

tố (n ≤ 231)

Cũng như bài toán 1, việc duyệt các số nguyên là bội của p từ1 đến n để chia cho p tìm số

mũ rồi lấy tổng các số mũ này là khôngthể thực hiên được

Ví dụ:

Nếun=231 còn p = 2 thì ta phải duyệt qua (n div p) số, đại lượngnày bằng 230

=1.073.741.824 tức là hơn 1 tỷ số cần phải duyệt.Nội chỉ việc cho biến i chạy qua 230 số này mà chưa làm gìcả cũng đã mất khoảng 10 giây rồi (nếu không tin bạn hãy viết

chươngtrình chỉ gồm 1 lệnh cho i chạy từ 1 đến 1 tỉ không làm gì cả vàviết hàm đếm thời gian xem)

Như vậy ta cần phải tìm 1 cách khác để tính số mũ của p Gọisi là số số chia hết cho pi

trong khoảng 1 n Số này bằng tổng của số các số chia hết cho p, p2, p3…trong khoảng 1 n Dễ thấy số mũ của p là s1+s2+…+sk với k lớn nhất sao cho pk≤ n

Vídụ: n=29 vàp =3 thì k=3, s1 =9, s2 =3, s3 =1 → Số mũ của 3 là s1+s2+s3 =13

Mặtkhác các số chia hết cho pi trong khoảng 1 n là: 1* pi, 2*pi, 3* pi, …, * pi → có

số Đây chính là nội dung củađịnh lý Lơgiăngđrơ: Số mũ của số nguyên tố p trong phân tích n!thành các thừa số nguyên tố là:

cho pi trong khoảng 1 (ndiv p)) áp dụng điều này với i=1 ta có được chươngtrình hàm tính số mũ của p trong phân tích ra thừa số nguyên tố củan!

functionSoMu(p:longint;n:longint):integer;

varcount:integer;

begin

count:=0;

Trang 5

while n<>0 do

begin

n:=n div p;

Count:=count + n;

end;

SoMu:=count;

end;

số nguyên nhỏ nhất sao cho n < pk

Cụthể trong bài này trường hợp lớn nhất là n = 231; p = 2 thì

k = log2231 = 31 so với 230 (nhỏ hơn34 triệu lần) !

Bài toán 3: Tìm số chữ số 0 tận cùng và chữ số tận cùng khác 0 của n! (n< 231) Dữ liệu nhập từ bàn phím số n và in kết quả sốchữ số 0 tận cùng và chữ số tận cùng khác 0 của n!

ra màn hình

Cơsở thuật toán: Ta thấy n! khi phân tích ra thừa số nguyên tố thìcó dạng

n! = 2SoMu(2,n) * 5SoMu(5,n) *…

Trong công thức Lơgiăngđrơ nếu p1< p2 thìSoMu(p1,n) ≥ SoMu(p2,n) nên số chữ số 0 tận cùng của n! chính làSoMu(5,n)

Đặt m = SoMu(2,n) - SoMu(5,n).Bỏ đi các chữ số 0 tận cùng thì ta có: Chữ số tận cùng

m mod 4 = 0, 1, 2, 3 thì 2m mod 10 = 6, 2, 4, 8 (trừtrường hợp m = 0) Công việc còn lại

là tìm hàm TanCung(n) (Nếu bâygiờ chỉ nói tận cùng thì ta hiểu là số đó đã được chia cho 2 và5 đến dư)

Ví dụ: Tận cùng của 10 là 1, của 14 là 7 …

Nếun tương đối nhỏ thì ta có thể duyệt bằng 1 vòng for để tìm tận cùngcủa n! Nhưng n

có thể lên tới 2 tỷ nên ta xây dựng hàm TanCung(n) nhưsau (với ví dụ n = 27):

Nếu n < 10 thì duyệt bình thường Xét n ≥10, ta tính tận cùng của tích (n mod 10) số

(temp=21*22*23*24*25*26*27=21*11*23*3*1*13*27=1*1*3*3*1*3*7=9)

temp:=1;

fori:=n+1-n mod 10 to n do

begin

tg:=i;

while not ođ(tg) do

tg:=tg shr 1;

while (tg mod 5=0) do

tg:=tg div 5;

temp:=temp*(tg mod 10) mod 10;

end;

temp:=temp mod 10;

Trang 6

n:=n-n mod 10;

VậyTanCung(n) = [temp*TanCung(n − n mod 10)] mod 10

Gánlại n:= n − n mod 10(n = 20) Ta phân hoạch các số từ 1 đến n thành 3phần:

-Các số không chia hết cho 2 và 5: Các số này có tận cùng là 1, 3,7, 9 ( 1, 3, 7, 9, 11, 13,

17, 19 ) mỗi loại có (n div 10) số nên tận cùngcủa tích các số này bằng tận cùng của (1*3*7*9)n div 10 = 9n div 10 Nếu (n div 10) chẵnthì số này bằng 1, lẻ thì bằng 9 (n=20, số này là 1)

if ođ(n div 10) then temp:=temp*9;{else temp:=temp*1}

(n=20 → temp=1*9=9)

-Các số là bội của 2 có dạng 2, 2*2, 2*3,…, 2*(n div 2) (2, 4, 6, 8, 10,12, 14, 16, 18, 20) Tận cùng của tích này cũng chính là tận cùng của1*2*3*…*(n div 2) =TanCung(n div 2) (Vì đã loại đi tất cả các thừa số2)

(n=20ta có 1*2*3*…*10 = TanCung(10))

-Các số là bội của 5 nhưng lẻ (không là bội của 2) có dạng 5, 5*3,5*5…5*t (t lẻ sao cho 5*t < n) (n=20 → t=3;gồm 2 số: 5, 15) Tận cùng của tích này bằng tận cùng của tích các

số lẻ 1*3*5*7*…*t (n=20 là 1*3) (vì đã loại đi tất cả các thừa số 5) Ta tính nó bằng hàm TanCungLe(n) (Tận cùng của các số lẻ không quá n)

Theo cách phân hoạch ta có (các số n sau là đã gán lại n = n− n mod 10):

TanCung(n):=temp*TanCung(n div 2)*TanCungLe(n div 5) mod 10

TanCung(27)=9*TanCung(10)*TanCungLe(4) mod 10

Cách xây dựng hàm TanCungLe(n) cũng tương tự như trên: n <10 duyệt bình thường Xét n ≥10, tính tận cùng của các số lẻ trong khoảng (n-n mod 10) n lưu vào biến temp Gán lại n:= n − n mod 10 Ta phân hoạch các số lẻ từ 1 n thành 2 phần:

-Các số không chia hết cho 5 có tận cùng la 1, 3, 7, 9 mỗi loại có (ndiv 10) số tính như phần trên

if ođ(n div 10) then temp:=temp*9;{else temp:=temp*1}

-Các số là bội của 5 có dạng 5, 5*3, 5*5,…5*t (t lẻ sao cho 5*t < n)

Tậncùng tích t số này chính là TanCungLe(n div 5)

Tacó TanCungLe(n)=temp * TanCungLe((n- n mod 10) div 5) mod 10;

Chương trình bài này cài đặt như sau:

{Timchu so cuoi cung khac khong cua n!}

{$A+,B-,D+,E+,F-,G-,I+,L+,N-,O-,P-,Q+,R+,S+,T-,V+,X+}

{$M65500,0,655360}

programChu_so_tan_cung_khac_0_cua_n_giai_thua;

usescrt;

varn,m,tc:longint;

functionTanCungLe(n:longint):integer;

vartemp,tg,i:longint;

begin

if n<=10 then

begin

temp:=1;

for i:=1 to n do

if (ođ(i) and (i<>5)) then

temp:=temp*i;

TanCungLe:=temp mod 10;

Trang 7

Exit;

end;

if not ođ(n) then n:=n-1;

if ođ(n div 10) then

temp:=9

else temp:=1;

for i:=n+1-n mod 10 to n do

if ođ(i) then

begin

tg:=i;

while (tg mod 5=0) do

tg:=tg div 5;

temp:=temp*(tg mod 10) mod 10;

end;

temp:=temp mod 10;

n:=n-n mod 10;

TanCungLe:=temp*TanCungLe(n div 5) mod 10; end;

functionTanCung(n:longint):integer;

vartemp,tg,i:longint;

begin

if n<=10 then

begin

temp:=1;

for i:=1 to n do

begin

tg:=i;

while not ođ(tg) do

tg:=tg shr 1;

if (tg mod 5 =0) then

tg:=tg div 5;

temp:=(temp*tg);

end;

TanCung:=temp mod 10;

Exit;

end;

if ođ(n div 10) then temp:=9

else temp:=1;

for i:=n+1-n mod 10 to n do

begin

tg:=i;

while not ođ(tg) do

tg:=tg shr 1;

while (tg mod 5=0) do

tg:=tg div 5;

temp:=temp*(tg mod 10) mod 10;

Trang 8

end;

temp:=temp mod 10;

n:=n-n mod 10;

TanCung:=temp*TanCung(n div 2)*TanCungLe(n div 5) mod 10;

end;

functionSoMu(p:longintr;n:longint):longint;

varcount:longint;

begin

count:=0;

while n<>0 do

begin

n:=n div p;

Count:=count+n;

end;

SoMu:=count;

end;

procedureSolve;

begin

Write('N=');Readln(n);

m:=SoMu(2,n)-SoMu(5,n);

if m=0 then tc:=1

else

case (m mod 4) of

0 : tc:=6;

1 : tc:=2;

2 : tc:=4;

3 : tc:=8;

end;

tc:=(tc*TanCung(n)) mod 10;

Writeln('Chu so tan cung khac 0 cua n! la : ',tc);

end;

BEGIN

Clrscr;

Solve;

Readln;

END

Với n < 231 bất kì thì thời gian tính toánkhông quá 1 giây Nếu làm bình thường bằng cách duyệt như với n ≤ 10 ở cài đặt trênthì chạy n = 10 triệu mất khoảng 73 giây (Gấp nhau đến hàng trăm lần).Như đã thấy, với cùng một bài toán vấn đề nhưng thuật toán và cáchcài đặt khác nhau thì hiệu quả của chương trình cài đặt có thể sẽkhác biệt nhau rất rõ ràng Vì vậy những kiến thức toán học dể chứngminh thuật toán và chương trình là rất cần thiết khi ta muốn tối ưuhoá một thuật toán nào đó Lần sau tôi sẽ xin trình bày với các bạnvề những kiến thức số học được ứng dụng trong giải các bài toántin

Ngày đăng: 07/09/2012, 10:55

TỪ KHÓA LIÊN QUAN

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

TÀI LIỆU LIÊN QUAN

w