01/10/2018, 09:06

Về thuật toán phân tích thừa số nguyên tô

Em đang học Pascal mà có tjuaatj toán phân tích một số ra thừa số các số nguyên tố

i:=2;
repeat
while (n mod i <> 0) do
i:=i+1;
write(i);
n:=n div i;
if n > 1 then write ('*');
until n = 1;

cho em hỏi tại sao nó lại bỏ qua các số không nguyên tố

rogp10 viết 11:10 ngày 01/10/2018

Vì nó chia cho cả lũy thừa của một số nguyên tố (power primes).
Mà nên sửa lại chạy tới sqrt thôi.

Giờ ta có n = p1^e1 * p2^e2 * ... sắp xếp theo chiều tăng của p[i].

Phần neo: Số đem chia đầu tiên luôn là một số nguyên tố vì hợp số phải chia hết cho một số nguyên tố nhỏ hơn, và áp dụng t/c bắc cầu.

Nhưng thế này vẫn chưa đủ để chứng minh tính đúng đắn. Thôi bạn thớt giải tiếp vậy.

Trần Hoàn viết 11:12 ngày 01/10/2018
i := 2;
while ( i ≤ sqrt(n)) do
    if (n mod i = 0) then 
        begin
            write(i,'*');
            n := n div i;
        end
    else
        i := i + 1;
write(n);
Sơn viết 11:07 ngày 01/10/2018

Mình chưa hiểu lắm tại mình hơi dốt toán

rogp10 viết 11:20 ngày 01/10/2018

(tiếp theo) vậy thì vòng lặp tạm dừng ở i = p1 vì p1 là nhỏ nhất rồi. Quan sát kĩ vòng lặp thì ta thấy rằng điều kiện dừng chia là n mod i != 0 nên sau đó i > p1.

Nếu n_mới = 1 (hay n_cũ = p1^e1) thì thuật toán dừng và chạy đúng.
Ngược lại n_mới = p2^e2 * p3^e3 * ... và ta lại trở lại giả thiết ban đầu: số chia tiếp theo phải là p2, v.v…do i <= p2 < p3 < …

NG viết 11:10 ngày 01/10/2018

Thay vì đặt điều kiện vòng lặp là i<= sqrt(n) sao mình không để (n > 1) ?
đỡ phải tính sqrt.

Trần Hoàn viết 11:18 ngày 01/10/2018

thế cũng được, nhiều cách mà.
Nhưng mà nếu điều kiện là n thì cuối cùng sẽ in ra n* chứ không phải n như cách của mình. Có thể dùng while (i<n) thì không phải tính sqrt.

NG viết 11:16 ngày 01/10/2018

def t(n, i=2):
    while (n > 1):
        if (n%i != 0):
            i += 1
        else:
            print (i)
            n = int(n/i)
            if n>1:
                print('*')

sửa lại chút cho phù hợp là được

NG viết 11:13 ngày 01/10/2018

Ai cho mình cái link chỉ up code lên với, copy paste ko dc @@

Trần Hoàn viết 11:20 ngày 01/10/2018

rogp10 viết 11:15 ngày 01/10/2018

Làm thế gặp số nguyên tố thì sẽ chạy từ 1 đến n nhé.

Có thể dùng while (i<n) thì không phải tính sqrt.

Nếu n là số nguyên tố thì cách đấy vẫn phải chạy từ 1 đến n thôi.

NG viết 11:08 ngày 01/10/2018

Hiểu, nhưng không biết complex của hai cách cái nào hơn cái nào, dù sao của sqrt cũng kha khá.
Mình nói leo phát cho bạn nào mới học lập trình: lưu sqrt(n) lại trong 1 biến nếu cần dùng nhiều lần để tiết kiệm, tránh phải tính đi tính lại 1 thứ tốn thời gian.

a = sqrt(n)
while (i<=a) do

Trần Hoàn viết 11:13 ngày 01/10/2018

n giảm dần mà, đâu phải tính đi tính lại đâu?
trường hợp xấu khi n là số nguyên tố hoặc chỉ chia hết cho 2, 3 và một số rất lớn thì while (i ≤ a) mới ít hơn while (i < n). Còn nếu như n kiểu như 100000000 thì cách while (i < n) lợi hơn.

NG viết 11:22 ngày 01/10/2018

uh nhỉ, mà thôi kệ đi, core i5 i7 xá gì chút xíu complex cho nhức đầu, hực

rogp10 viết 11:21 ngày 01/10/2018

Thế sao không tính một lần sqrt()? Có mất gì đâu.

(pseudocode)

: Input: n

: x := sqrt(n), i := 2

for i:=2 to x do
   while(n mod i = 0) begin 
       n := n div i;
       if n != 1 then print('*');
   end;
NG viết 11:08 ngày 01/10/2018

Thì mình đề nghị ở post trước đó

Nguyen Gia Huy viết 11:11 ngày 01/10/2018

Trả lời cho câu hỏi của bạn:

Các số không phải là số nguyên tố đều có thể phân tích thành tích của các số nguyên tố nhỏ hơn có nghĩa là nếu n đã không chia hết cho các số nguyên tố trước đó thì sẽ không chia hết cho các số đứng sau.
VD n=14
vòng lặp 1: 14/2 =7
vòng lặp 2: 7/3 <>0
vòng lặp 3: 7/4 <>0 (n đã không chia hết cho 2, nên chắc chắn sẽ không chia hết cho 4)
vòng lặp 4: 7/5 <>0
vòng lặp 5: 7/6 <>0 (n đã không chia hết cho 2, nên chắc chắn sẽ không chia hết cho 6)
vòng lặp 6: 7/7 =1

Thuật toán bạn đưa ra không bỏ qua các số không phải là số nguyên tố mà do số ấy không phải là ước của n nên không được in ra.

Hope it help you

Tuấn Tử Tế viết 11:14 ngày 01/10/2018

Bạn Gia Huy đã trả lời đúng câu hỏi của bạn rồi đấy. Khi bạn kiểm tra đến 1 số bất kỳ không phải số NT, thì nó chắc chắn sẽ không chia hết cho các số đấy, vì ước của số đấy nó cũng đã không chia hết rồi.
Còn về thuật toán thì chuẩn nhất rồi, không cần phải sqrt đâu. Vì số vòng lặp là số ước của nó nên ít hơn việc bạn đặt vòng lặp for từ 1 đến x=sqrt(n).

rogp10 viết 11:07 ngày 01/10/2018

Nếu n là số nguyên tố thì vẫn chạy từ 1 đến n đấy

Trần Hoàn viết 11:11 ngày 01/10/2018

Cách nhanh nhất ý, là “cache”.
Tức là liệt kê tất cả các số nguyên tố nhỏ hơn max của longint cho vào một file, coi như cái sàng, sau này có làm với số khác thì dùng cái đó :v

Tuấn Tử Tế viết 11:08 ngày 01/10/2018

Thằng cu mới học Pascal mà đã thế thì chết à. Nói chung mức độ học cơ bản thì hiểu bản chất của vấn đề là ok rồi. Nếu đưa ra được các thuật toán tối ưu nhất thì càng OK.

Bài liên quan
0