Cấu trúc dữ liệu cho xúc xắc được tải?


130

Giả sử rằng tôi có một khuôn mặt được tải n mặt trong đó mỗi bên k có một số xác suất p k xuất hiện khi tôi cuộn nó. Tôi tò mò liệu có thuật toán tốt để lưu trữ thông tin này một cách tĩnh (tức là đối với một tập hợp xác suất cố định) để tôi có thể mô phỏng hiệu quả một cuộn súc sắc ngẫu nhiên.

Hiện tại, tôi có một giải pháp O (lg n) cho vấn đề này. Ý tưởng là lưu trữ một bảng xác suất tích lũy của các cạnh k đầu tiên cho tất cả k, chúng tạo ra một số thực ngẫu nhiên trong phạm vi [0, 1) và thực hiện tìm kiếm nhị phân trên bảng để lấy chỉ số lớn nhất có tích lũy giá trị không lớn hơn giá trị được chọn. Tôi khá thích giải pháp này, nhưng có vẻ kỳ lạ là thời gian chạy không tính đến xác suất. Đặc biệt, trong các trường hợp cực đoan của một phía luôn xuất hiện hoặc các giá trị được phân phối đồng đều, có thể tạo ra kết quả của cuộn trong O (1) bằng cách sử dụng một cách tiếp cận ngây thơ, mặc dù giải pháp của tôi vẫn sẽ thực hiện nhiều bước logarit.

Có ai có bất kỳ đề xuất nào về cách giải quyết vấn đề này theo cách nào đó "thích nghi" trong thời gian chạy không?

EDIT : Dựa trên các câu trả lời cho câu hỏi này, tôi đã viết một bài báo mô tả nhiều cách tiếp cận vấn đề này , cùng với các phân tích của họ. Có vẻ như việc Vose thực hiện phương pháp bí danh cho time (n) thời gian tiền xử lý và thời gian O (1) cho mỗi lần lăn, điều này thực sự ấn tượng. Hy vọng rằng đây là một bổ sung hữu ích cho các thông tin có trong các câu trả lời!


2
Thật hợp lý khi tồn tại giải pháp O (1) cho từng trường hợp cụ thể .
Tim

Câu trả lời:


117

Bạn đang tìm kiếm phương thức bí danh cung cấp phương thức O (1) để tạo phân phối xác suất rời rạc cố định (giả sử bạn có thể truy cập các mục trong một mảng có độ dài n trong thời gian không đổi) với thiết lập O (n) một lần . Bạn có thể tìm thấy nó được ghi lại trong chương 3 (PDF) của "Thế hệ biến thể ngẫu nhiên không đồng nhất" của Luc Devroye.

Ý tưởng là lấy mảng xác suất của bạn p k và tạo ra ba mảng phần tử n mới, q k , a k và b k . Mỗi q k là một xác suất trong khoảng từ 0 đến 1 và mỗi a k và b k là một số nguyên nằm trong khoảng từ 1 đến n.

Chúng tôi tạo các số ngẫu nhiên từ 1 đến n bằng cách tạo hai số ngẫu nhiên, r và s, từ 0 đến 1. Đặt i = floor (r * N) +1. Nếu q i <s thì trả về a i khác trả về b i . Công việc trong phương pháp bí danh là tìm ra cách sản xuất q k , a k và b k .


Đối với một thuật toán hữu ích như vậy, Phương pháp bí danh đáng ngạc nhiên là không nổi tiếng lắm.
mhum

Đối với bản ghi: Tôi đã xuất bản một thư viện C nhỏ để lấy mẫu ngẫu nhiên bằng phương pháp bí danh apps.jcns.fz-juelich.de/ransampl .
Joachim W

1
việc triển khai cụ thể phương pháp bí danh có thể chậm hơn sau đó một phương pháp có độ phức tạp thời gian tồi tệ hơn như Roulette Wheel cho một nsố lượng ngẫu nhiên nhất định được chọn để tạo do các yếu tố không đổi liên quan đến việc thực hiện các thuật toán.
jfs

4

Sử dụng cây tìm kiếm nhị phân cân bằng (hoặc tìm kiếm nhị phân trong một mảng) và nhận độ phức tạp O (log n). Có một nút cho mỗi kết quả chết và có các khóa là khoảng thời gian sẽ kích hoạt kết quả đó.

function get_result(node, seed):
    if seed < node.interval.start:
        return get_result(node.left_child, seed)
    else if seed < node.interval.end:
        // start <= seed < end
        return node.result
    else:
        return get_result(node.right_child, seed)

Điểm hay của giải pháp này là rất đơn giản để thực hiện nhưng vẫn có độ phức tạp tốt.


Cây nhị phân làm bằng tay như trên rất đơn giản để thực hiện nhưng nó không được đảm bảo cân bằng
yusong

Bạn có thể đảm bảo rằng nó được cân bằng nếu bạn xây dựng nó theo đúng thứ tự.
hugomg

3

Tôi đang nghĩ đến việc tạo hạt cho bàn của bạn.

Thay vì có một bảng có tích lũy cho mỗi giá trị chết, bạn có thể tạo một mảng số nguyên có độ dài xN, trong đó x lý tưởng là một số cao để tăng độ chính xác của xác suất.

Dân số mảng này bằng cách sử dụng chỉ mục (được chuẩn hóa bởi xN) làm giá trị tích lũy và, trong mỗi 'vị trí' trong mảng, lưu trữ cuộn xúc xắc sẽ xuất hiện nếu chỉ số này xuất hiện.

Có lẽ tôi có thể giải thích dễ dàng hơn với một ví dụ:

Sử dụng ba con xúc xắc: P (1) = 0,2, P (2) = 0,5, P (3) = 0,3

Tạo một mảng, trong trường hợp này tôi sẽ chọn một độ dài đơn giản, giả sử 10. (nghĩa là, x = 3.33333)

arr[0] = 1,
arr[1] = 1,
arr[2] = 2,
arr[3] = 2,
arr[4] = 2,
arr[5] = 2,
arr[6] = 2,
arr[7] = 3,
arr[8] = 3,
arr[9] = 3

Sau đó, để có được xác suất, chỉ cần chọn ngẫu nhiên một số trong khoảng từ 0 đến 10 và chỉ cần truy cập vào chỉ mục đó.

Phương pháp này có thể mất độ chính xác, nhưng tăng x và độ chính xác sẽ là đủ.


1
Để có độ chính xác đầy đủ, bạn có thể thực hiện tra cứu mảng như một bước đầu tiên và đối với các khoảng mảng tương ứng với nhiều phía thực hiện tìm kiếm ở đó.
aaz

1

Có nhiều cách để tạo một số nguyên ngẫu nhiên với phân phối tùy chỉnh (còn được gọi là phân phối rời rạc ). Sự lựa chọn phụ thuộc vào nhiều thứ, bao gồm số lượng số nguyên để chọn, hình dạng phân phối và liệu phân phối sẽ thay đổi theo thời gian.

Một trong những cách đơn giản nhất để chọn số nguyên có hàm trọng số tùy chỉnh f(x)là phương pháp lấy mẫu từ chối . Các giả định sau đây cho rằng giá trị cao nhất có thể fmax. Độ phức tạp thời gian để lấy mẫu từ chối trung bình không đổi, nhưng phụ thuộc rất lớn vào hình dạng của phân phối và có trường hợp xấu nhất là chạy mãi mãi. Để chọn một số nguyên trong [1, k] bằng cách sử dụng lấy mẫu từ chối:

  1. Chọn một số nguyên ngẫu nhiên thống nhất itrong [1, k].
  2. Với xác suất f(i)/max, trở lại i. Nếu không, hãy đến bước 1.

Các thuật toán khác có thời gian lấy mẫu trung bình không phụ thuộc quá nhiều vào phân phối (thường là hằng số hoặc logarit), nhưng thường yêu cầu bạn phải tính toán trước các trọng số trong bước thiết lập và lưu trữ chúng trong cấu trúc dữ liệu. Một số trong số chúng cũng kinh tế về số lượng bit ngẫu nhiên mà chúng sử dụng trung bình. Nhiều thuật toán trong số này đã được giới thiệu sau năm 2011, và chúng bao gồm

  • cấu trúc dữ liệu cô đọng của Giannmann Larsen ("Lấy mẫu ngắn gọn từ các bản phân phối rời rạc", 2012),
  • Tìm kiếm đa cấp của Yunpeng Tang ("Một nghiên cứu thực nghiệm về phương pháp lấy mẫu ngẫu nhiên để thay đổi phân phối rời rạc", 2019), và
  • các Dice lăn nhanh Loaded (2020).

Các thuật toán khác bao gồm phương pháp bí danh (đã được đề cập trong bài viết của bạn), thuật toán Knuth Yao Yao, cấu trúc dữ liệu MVN, v.v. Xem phần " Lưu ý về thuật toán lựa chọn có trọng số " của tôi để biết bản khảo sát.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.