"Hacker" trong tên của bài kiểm tra cho thấy chúng tôi cố gắng tìm một giải pháp định hướng điện toán.
Do đó, hãy bắt đầu với một chương trình liệt kê (a) các trường hợp "thuận lợi" trong đó một số nguyên gấp đôi số kia và (b) tất cả các trường hợp có thể. Câu trả lời sau đó sẽ là tỷ lệ của họ. Tôi đã mã hóa một giải pháp chung. Đầu vào của nó là một số nguyên dương n
và đầu ra của nó là xác suất.
n=100
all=favorable=0
for i=1 to n
for j=1 to n
if (i != j) all=all+1 {1}
if (j == 2*i) favorable = favorable+1 {2}
if (i == 2*j) favorable = favorable+1 {3}
return(favorable / all)
(Bằng chứng về tính chính xác phụ thuộc vào thực tế là cho bất kỳ số dương nào .)tôi ≠ 2 tôiTôi
Chương trình này yêu cầu bài kiểm tra và tối đa tăng cho mỗi lần lặp của vòng lặp bên trong. Do đó, nó cần từ đến tính toán mỗi khi vòng lặp bên trong được thực hiện, hoặc tổng thể đến . Đó là hiệu suất : OK cho nhỏ như , nhưng khủng khiếp khi vượt quá hoặc hơn.333 n6 n3 n26 n2Ô ( n2)nn=100n10000
Là một hacker, một trong những điều đầu tiên bạn sẽ muốn làm là loại bỏ hiệu suất bậc hai bằng cách đơn giản hóa vòng lặp bên trong (nếu có thể). Để kết thúc này, một cách có hệ thống đi qua các dòng trong vòng lặp bên trong (như được đánh số) và lưu ý những điều sau:
Dòng 1 được thực hiện tất cả nhưng một lần cho mỗi giá trị i
và do đó all
được tăng lần. Do đó, để tính toán , vòng lặp có thể được thay thế bằng cách tăng theo .n−1all
j
all
n-1
Dòng 2 được thực hiện chính xác một lần khi và mặt khác thì không. Do đó nó có thể được thay thế bằng incrementing bởi bất cứ khi nào .2i≤nall
12i≤n
Dòng 3 được thực thi khi được cung cấp i
là chẵn.
Đây là chương trình chuyển đổi.
n=100
all=favorable=0
for i=1 to n
all = all + (n-1) {1'}
if (2*i <= n) favorable = favorable+1 {2'}
if (even(i)) favorable = favorable+1 {3'}
return(favorable / all)
Chúng ta có thể đi xa hơn và loại bỏ vòng lặp của nó?
Dòng 1 'được thực hiện lần. Do đó được tăng lên bởi .nall
n*(n-1)
Dòng 2 'chỉ được thực hiện khi . Một cách để tính điều này là (số nguyên lớn nhất nhỏ hơn hoặc bằng ).2i≤n⌊n/2⌋n/2
Dòng 3 'chỉ được thực hiện cho các giá trị chẵn của . Một lần nữa, điều đó xảy ra lần.⌊ n / 2 ⌋i⌊n/2⌋
Chuyển đổi thứ hai của chương trình là:
n=100
all=favorable=0 {0}
all = all + n * (n-1) {1''}
favorable = favorable + floor(n/2) {2''}
favorable = favorable + floor(n/2) {3''}
return(favorable / all)
Đây đã là một thành tựu to lớn: một thuật toán đã được giảm xuống một Thuật toán (có thể được coi là một "công thức khép kín" cho câu trả lời).O ( 1 )O(n2)O(1)
Cuối cùng, có một số phép biến đổi đại số đơn giản mà chúng ta có thể thực hiện bằng cách đưa phần khởi tạo (dòng 0) vào lần sử dụng đầu tiên của mỗi biến và kết hợp các dòng 2 '' và 3 '':
n=100
all = n * (n-1)
favorable = 2 * floor(n/2)
return(favorable / all)
Tại thời điểm này, một con người có thể thực hiện chương trình. Hãy làm điều đó với :n=100
all = 100 * (100-1) = 100*99
favorable = 2 * floor(100/2) = 2*50 = 100
favorable/all = 100 / (100*99) = 1/99
Do đó, đầu ra là .1/99
Tóm lại, một thuật toán brute-force có thể được chuyển đổi một cách có hệ thống bằng cách sử dụng các quy tắc viết lại chương trình đơn giản thành một chương trình đẹp, thanh lịch .O(1)