Tôi nghĩ rằng tôi có bốn câu trả lời, hai câu trả lời chính xác như của @Adam Rosenfield nhưng không có vấn đề vòng lặp vô hạn và hai câu hỏi khác với giải pháp gần như hoàn hảo nhưng thực hiện nhanh hơn lần đầu tiên.
Giải pháp chính xác tốt nhất yêu cầu 7 cuộc gọi đến rand5
, nhưng hãy tiếp tục để hiểu.
Phương pháp 1 - Chính xác
Điểm mạnh của câu trả lời của Adam là nó mang lại sự phân phối đồng đều hoàn hảo và có xác suất rất cao (21/25) chỉ cần hai cuộc gọi đến rand5 (). Tuy nhiên, trường hợp xấu nhất là vòng lặp vô hạn.
Giải pháp đầu tiên dưới đây cũng cung cấp một phân phối thống nhất hoàn hảo, nhưng yêu cầu tổng cộng 42 cuộc gọi đến rand5
. Không có vòng lặp vô hạn.
Đây là một triển khai R:
rand5 <- function() sample(1:5,1)
rand7 <- function() (sum(sapply(0:6, function(i) i + rand5() + rand5()*2 + rand5()*3 + rand5()*4 + rand5()*5 + rand5()*6)) %% 7) + 1
Đối với những người không quen thuộc với R, đây là phiên bản đơn giản hóa:
rand7 = function(){
r = 0
for(i in 0:6){
r = r + i + rand5() + rand5()*2 + rand5()*3 + rand5()*4 + rand5()*5 + rand5()*6
}
return r %% 7 + 1
}
Việc phân phối rand5
sẽ được bảo tồn. Nếu chúng ta làm toán, mỗi trong số 7 lần lặp của vòng lặp có 5 ^ 6 kết hợp có thể, do đó tổng số kết hợp có thể là (7 * 5^6) %% 7 = 0
. Do đó chúng ta có thể chia các số ngẫu nhiên được tạo thành các nhóm bằng nhau 7. Xem phương pháp hai để thảo luận thêm về điều này.
Dưới đây là tất cả các kết hợp có thể:
table(apply(expand.grid(c(outer(1:5,0:6,"+")),(1:5)*2,(1:5)*3,(1:5)*4,(1:5)*5,(1:5)*6),1,sum) %% 7 + 1)
1 2 3 4 5 6 7
15625 15625 15625 15625 15625 15625 15625
Tôi nghĩ rằng nó thẳng tiến để cho thấy rằng phương pháp của Adam sẽ chạy nhanh hơn nhiều. Xác suất có từ 42 cuộc gọi trở lên rand5
trong giải pháp của Adam là rất nhỏ ( (4/25)^21 ~ 10^(-17)
).
Phương pháp 2 - Không chính xác
Bây giờ phương thức thứ hai, gần như thống nhất, nhưng yêu cầu 6 cuộc gọi đến rand5
:
rand7 <- function() (sum(sapply(1:6,function(i) i*rand5())) %% 7) + 1
Đây là một phiên bản đơn giản hóa:
rand7 = function(){
r = 0
for(i in 1:6){
r = r + i*rand5()
}
return r %% 7 + 1
}
Đây thực chất là một lần lặp của phương thức 1. Nếu chúng ta tạo ra tất cả các kết hợp có thể, thì đây là kết quả tính:
table(apply(expand.grid(1:5,(1:5)*2,(1:5)*3,(1:5)*4,(1:5)*5,(1:5)*6),1,sum) %% 7 + 1)
1 2 3 4 5 6 7
2233 2232 2232 2232 2232 2232 2232
Một số sẽ xuất hiện một lần nữa trong 5^6 = 15625
các thử nghiệm.
Bây giờ, trong Phương pháp 1, bằng cách thêm 1 đến 6, chúng tôi di chuyển số 2233 đến từng điểm liên tiếp. Do đó, tổng số kết hợp sẽ khớp với nhau. Điều này hoạt động vì 5 ^ 6 %% 7 = 1, và sau đó chúng tôi thực hiện 7 biến thể phù hợp, vì vậy (7 * 5 ^ 6 %% 7 = 0).
Phương pháp 3 - Chính xác
Nếu đối số của phương thức 1 và 2 được hiểu, phương thức 3 theo sau và chỉ yêu cầu 7 cuộc gọi đến rand5
. Tại thời điểm này, tôi cảm thấy đây là số lượng cuộc gọi tối thiểu cần thiết cho một giải pháp chính xác.
Đây là một triển khai R:
rand5 <- function() sample(1:5,1)
rand7 <- function() (sum(sapply(1:7, function(i) i * rand5())) %% 7) + 1
Đối với những người không quen thuộc với R, đây là phiên bản đơn giản hóa:
rand7 = function(){
r = 0
for(i in 1:7){
r = r + i * rand5()
}
return r %% 7 + 1
}
Việc phân phối rand5
sẽ được bảo tồn. Nếu chúng ta làm toán, mỗi trong số 7 lần lặp của vòng lặp có 5 kết quả có thể xảy ra, do đó tổng số kết hợp có thể là (7 * 5) %% 7 = 0
. Do đó, chúng ta có thể chia các số ngẫu nhiên được tạo thành các nhóm bằng nhau 7. Xem phương pháp một và hai để thảo luận thêm về điều này.
Dưới đây là tất cả các kết hợp có thể:
table(apply(expand.grid(0:6,(1:5)),1,sum) %% 7 + 1)
1 2 3 4 5 6 7
5 5 5 5 5 5 5
Tôi nghĩ rằng nó thẳng tiến để cho thấy rằng phương pháp của Adam vẫn sẽ chạy nhanh hơn. Xác suất có 7 cuộc gọi trở lên rand5
trong giải pháp của Adam vẫn còn nhỏ ( (4/25)^3 ~ 0.004
).
Phương pháp 4 - Không chính xác
Đây là một biến thể nhỏ của phương pháp thứ hai. Nó gần như thống nhất, nhưng yêu cầu 7 cuộc gọi đến rand5
, đó là một bổ sung cho phương thức 2:
rand7 <- function() (rand5() + sum(sapply(1:6,function(i) i*rand5())) %% 7) + 1
Đây là một phiên bản đơn giản hóa:
rand7 = function(){
r = 0
for(i in 1:6){
r = r + i*rand5()
}
return (r+rand5()) %% 7 + 1
}
Nếu chúng tôi tạo ra tất cả các kết hợp có thể, đây là kết quả tính:
table(apply(expand.grid(1:5,(1:5)*2,(1:5)*3,(1:5)*4,(1:5)*5,(1:5)*6,1:5),1,sum) %% 7 + 1)
1 2 3 4 5 6 7
11160 11161 11161 11161 11161 11161 11160
Hai số sẽ xuất hiện một lần ít hơn trong 5^7 = 78125
các thử nghiệm. Đối với hầu hết các mục đích, tôi có thể sống với điều đó.