Làm cách nào để tạo một bộ sưu tập có trọng số và sau đó chọn một yếu tố ngẫu nhiên từ nó?


34

Tôi có một hộp loot mà tôi muốn điền vào một mục ngẫu nhiên. Nhưng tôi muốn mỗi mục có cơ hội được chọn khác nhau. Ví dụ:

  • 5% cơ hội 10 vàng
  • 20% cơ hội kiếm
  • 45% cơ hội che chắn
  • 20% cơ hội của áo giáp
  • 10% cơ hội thuốc

Làm cách nào tôi có thể làm cho nó để tôi chọn chính xác một trong các mục ở trên, trong đó các tỷ lệ phần trăm đó là cơ hội tương ứng để nhận được các chiến lợi phẩm?


1
Về mặt lý thuyết, FYI, O (1) cho mỗi mẫu có thể cho bất kỳ phân phối hữu hạn nào, ngay cả một phân phối có các mục thay đổi linh hoạt. Xem ví dụ: cstheory.stackexchange.com/questions/37648/ săn .
Neal Young

Câu trả lời:


37

Giải pháp xác suất mã hóa mềm

Giải pháp xác suất mã hóa cứng có nhược điểm là bạn cần đặt xác suất trong mã của mình. Bạn không thể xác định chúng trong thời gian chạy. Nó cũng khó để duy trì.

Đây là một phiên bản động của cùng một thuật toán.

  1. Tạo một loạt các cặp vật phẩm thực tế và trọng lượng của từng vật phẩm
  2. Khi bạn thêm một mục, trọng lượng của mục cần phải là trọng lượng riêng của nó cộng với tổng trọng số của tất cả các mục đã có trong mảng. Vì vậy, bạn nên theo dõi tổng riêng. Đặc biệt bởi vì bạn sẽ cần nó cho bước tiếp theo.
  3. Để truy xuất một đối tượng, tạo một số ngẫu nhiên trong khoảng từ 0 đến tổng trọng số của tất cả các mục
  4. Lặp lại mảng từ đầu đến cuối cho đến khi bạn tìm thấy một mục có trọng số lớn hơn hoặc bằng số ngẫu nhiên

Dưới đây là một triển khai mẫu trong Java dưới dạng một lớp mẫu mà bạn có thể khởi tạo cho bất kỳ đối tượng nào mà trò chơi của bạn sử dụng. Sau đó, bạn có thể thêm các đối tượng với phương thức .addEntry(object, relativeWeight)và chọn một trong các mục bạn đã thêm trước đó với.get()

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class WeightedRandomBag<T extends Object> {

    private class Entry {
        double accumulatedWeight;
        T object;
    }

    private List<Entry> entries = new ArrayList<>();
    private double accumulatedWeight;
    private Random rand = new Random();

    public void addEntry(T object, double weight) {
        accumulatedWeight += weight;
        Entry e = new Entry();
        e.object = object;
        e.accumulatedWeight = accumulatedWeight;
        entries.add(e);
    }

    public T getRandom() {
        double r = rand.nextDouble() * accumulatedWeight;

        for (Entry entry: entries) {
            if (entry.accumulatedWeight >= r) {
                return entry.object;
            }
        }
        return null; //should only happen when there are no entries
    }
}

Sử dụng:

WeightedRandomBag<String> itemDrops = new WeightedRandomBag<>();

// Setup - a real game would read this information from a configuration file or database
itemDrops.addEntry("10 Gold",  5.0);
itemDrops.addEntry("Sword",   20.0);
itemDrops.addEntry("Shield",  45.0);
itemDrops.addEntry("Armor",   20.0);
itemDrops.addEntry("Potion",  10.0);

// drawing random entries from it
for (int i = 0; i < 20; i++) {
    System.out.println(itemDrops.getRandom());
}

Đây là cùng một lớp được triển khai trong C # cho dự án Unity, XNA hoặc MonoGame của bạn:

using System;
using System.Collections.Generic;

class WeightedRandomBag<T>  {

    private struct Entry {
        public double accumulatedWeight;
        public T item;
    }

    private List<Entry> entries = new List<Entry>();
    private double accumulatedWeight;
    private Random rand = new Random();

    public void AddEntry(T item, double weight) {
        accumulatedWeight += weight;
        entries.Add(new Entry { item = item, accumulatedWeight = accumulatedWeight });
    }

    public T GetRandom() {
        double r = rand.NextDouble() * accumulatedWeight;

        foreach (Entry entry in entries) {
            if (entry.accumulatedWeight >= r) {
                return entry.item;
            }
        }
        return default(T); //should only happen when there are no entries
    }
}

Và đây là một trong JavaScript :

var WeightedRandomBag = function() {

    var entries = [];
    var accumulatedWeight = 0.0;

    this.addEntry = function(object, weight) {
        accumulatedWeight += weight;
        entries.push( { object: object, accumulatedWeight: accumulatedWeight });
    }

    this.getRandom = function() {
        var r = Math.random() * accumulatedWeight;
        return entries.find(function(entry) {
            return entry.accumulatedWeight >= r;
        }).object;
    }   
}

Chuyên nghiệp:

  • Có thể xử lý bất kỳ tỷ lệ trọng lượng. Bạn có thể có các vật phẩm với xác suất thiên văn nhỏ trong tập hợp nếu bạn muốn. Các trọng số cũng không cần thêm tới 100.
  • Bạn có thể đọc các mục và trọng lượng trong thời gian chạy
  • Sử dụng bộ nhớ tỷ lệ thuận với số lượng mục trong mảng

Contra:

  • Yêu cầu thêm một số chương trình để có được quyền
  • Trong trường hợp xấu nhất, bạn có thể phải lặp lại toàn bộ mảng ( O(n)độ phức tạp thời gian chạy). Vì vậy, khi bạn có một bộ vật phẩm rất lớn và vẽ rất thường xuyên, nó có thể trở nên chậm chạp. Một tối ưu hóa đơn giản là đặt các mục có thể xảy ra đầu tiên để thuật toán chấm dứt sớm trong hầu hết các trường hợp. Một tối ưu hóa phức tạp hơn bạn có thể làm là khai thác thực tế là mảng được sắp xếp và thực hiện tìm kiếm chia đôi. Điều này chỉ mất O(log n)thời gian.
  • Bạn cần xây dựng danh sách trong bộ nhớ trước khi có thể sử dụng nó (mặc dù bạn có thể dễ dàng thêm các mục trong thời gian chạy. Việc xóa các mục cũng có thể được thêm vào, nhưng điều đó sẽ yêu cầu cập nhật trọng số tích lũy của tất cả các mục xuất hiện sau mục bị xóa một lần nữa có O(n)thời gian chạy tồi tệ nhất)

2
Mã C # có thể được viết bằng LINQ: return entry.FirstOrDefault (e => e.accumulation Weight> = r). Quan trọng hơn, có một khả năng nhỏ là do mất độ chính xác của dấu phẩy động, thuật toán này sẽ trả về null nếu giá trị ngẫu nhiên chỉ lớn hơn một chút so với giá trị tích lũy. Để phòng ngừa, bạn có thể thêm một giá trị nhỏ (giả sử là 1.0) vào phần tử cuối cùng, nhưng sau đó bạn sẽ phải nêu rõ trong mã của mình rằng danh sách là cuối cùng.
IMil

1
Một biến thể nhỏ trên này tôi đã sử dụng cá nhân, nếu bạn muốn các giá trị trọng lượng trong thời gian chạy không bị thay đổi thành giá trị trọng số cộng với tất cả trước đó, bạn có thể trừ trọng số của từng mục nhập đã qua khỏi giá trị ngẫu nhiên của mình, dừng khi giá trị ngẫu nhiên nhỏ hơn trọng lượng vật phẩm hiện tại (hoặc khi trừ đi trọng lượng làm cho giá trị <0)
Lunin

2
@ BlueRaja-DannyPflughoeft tối ưu hóa sớm ... câu hỏi là về việc chọn một đối tượng từ một hộp loot mở. Ai sẽ mở 1000 hộp mỗi giây?
IMil

4
@IMil: Không, câu hỏi là một câu hỏi tổng quát để chọn các mục có trọng số ngẫu nhiên . Đối với lootbox cụ thể, câu trả lời này có thể tốt vì có một số lượng nhỏ vật phẩm và xác suất không thay đổi (mặc dù, vì chúng thường được thực hiện trên máy chủ, 1000 / giây không phải là không thực tế đối với một trò chơi phổ biến) .
BlueRaja - Daniel Pflughoeft

4
@opa sau đó gắn cờ để đóng như một bản dupe. Có thực sự sai khi đưa ra một câu trả lời tốt chỉ vì câu hỏi đã được hỏi trước đó?
Baldrickk

27

Lưu ý: Tôi đã tạo thư viện C # cho vấn đề chính xác này

Các giải pháp khác đều ổn nếu bạn chỉ có một số lượng nhỏ các mặt hàng và xác suất của bạn không bao giờ thay đổi. Tuy nhiên, với nhiều mục hoặc thay đổi xác suất (ví dụ: xóa các mục sau khi chọn chúng) , bạn sẽ muốn thứ gì đó mạnh mẽ hơn.

Dưới đây là hai giải pháp phổ biến nhất (cả hai đều được bao gồm trong thư viện trên)

Phương pháp bí danh của Walker

Một giải pháp thông minh cực kỳ nhanh ( O(1)!) Nếu xác suất của bạn không đổi. Về bản chất, thuật toán tạo ra một bảng phi tiêu 2D ("bảng bí danh") ra khỏi xác suất của bạn và ném phi tiêu vào nó.

Bảng quảng cáo

rất nhiều bài viết trực tuyến về cách thức hoạt động nếu bạn muốn tìm hiểu thêm.

Vấn đề duy nhất là nếu xác suất của bạn thay đổi, bạn cần tạo lại bảng bí danh, tốc độ chậm. Do đó, nếu bạn cần xóa các mục sau khi chúng được chọn, đây không phải là giải pháp cho bạn.

Giải pháp dựa trên cây

Giải pháp phổ biến khác là tạo một mảng trong đó mỗi mục lưu trữ tổng xác suất của nó và tất cả các mục trước nó. Sau đó, chỉ cần tạo một số ngẫu nhiên từ [0,1) và thực hiện tìm kiếm nhị phân cho số đó nằm trong danh sách.

Giải pháp này rất dễ mã hóa / hiểu, nhưng thực hiện lựa chọn chậm hơn Phương pháp bí danh của Walker và việc thay đổi xác suất vẫn còn O(n). Chúng ta có thể cải thiện nó bằng cách biến mảng thành cây tìm kiếm nhị phân, trong đó mỗi nút theo dõi tổng xác suất trong tất cả các mục trong cây con của nó. Sau đó, khi chúng ta tạo số từ [0,1), chúng ta có thể đi xuống cây để tìm vật phẩm mà nó đại diện.

Điều này cho phép chúng tôi O(log n)chọn một mục thay đổi xác suất! Điều này làm cho NextWithRemoval()cực kỳ nhanh chóng!

Kết quả

Dưới đây là một số điểm chuẩn nhanh từ thư viện trên, so sánh hai cách tiếp cận này

         Điểm chuẩn của weightedRandomizer | Cây | Bàn
-------------------------------------------------- ---------------------------------
Thêm () x10000 + NextWithReplocation () x10: | 4 ms | 2 ms
Thêm () x10000 + NextWithReplocation () x10000: | 7 ms | 4 ms
Thêm () x10000 + NextWithReplocation () x100000: | 35 ms | 28 ms
(Thêm () + NextWithReplocation ()) x10000 (xen kẽ) | 8 ms | 5403 ms
Thêm () x10000 + NextWithRemoval () x10000: | 10 ms | 5948 ms

Vì vậy, như bạn có thể thấy, trong trường hợp đặc biệt về xác suất tĩnh (không thay đổi), phương pháp Bí danh của Walker nhanh hơn khoảng 50 - 100%. Nhưng trong các trường hợp năng động hơn, cây nhanh hơn nhiều bậc !


Giải pháp dựa trên cây cũng cho chúng ta thời gian chạy ( nlog(n)) tốt khi sắp xếp các mục theo trọng lượng.
Nathan Merrill

2
Tôi nghi ngờ về kết quả của bạn, nhưng đây là câu trả lời chính xác. Bạn không chắc chắn lý do tại sao đây không phải là câu trả lời đầu, coi đây thực sự là cách kinh điển để xử lý vấn đề này.
whn

Tập tin nào chứa giải pháp dựa trên cây? Thứ hai, bảng điểm chuẩn của bạn: có phải là Bí danh của Walker là cột "bảng" không?
Yakk

1
@Yakk: Mã cho giải pháp dựa trên cây là ở đây . Nó được xây dựng dựa trên việc triển khai nguồn mở của cây AA . Và "có" cho câu hỏi thứ hai của bạn.
BlueRaja - Daniel Pflughoeft

1
Phần Walker chỉ đẹp liên kết.
Tích lũy

17

Giải pháp bánh xe may mắn

Bạn có thể sử dụng phương pháp này khi xác suất trong nhóm vật phẩm của bạn có mẫu số chung khá lớn và bạn cần rút ra từ đó rất thường xuyên.

Tạo một loạt các tùy chọn. Nhưng đặt từng yếu tố vào nó nhiều lần, với số lượng trùng lặp của từng yếu tố tỷ lệ thuận với cơ hội xuất hiện của nó. Đối với ví dụ trên, tất cả các phần tử có xác suất là bội số của 5%, vì vậy bạn có thể tạo một mảng gồm 20 phần tử như thế này:

10 gold
sword
sword
sword
sword
shield
shield
shield
shield
shield
shield
shield
armor
armor
armor
armor
potion
potion

Sau đó, chỉ cần chọn một phần tử ngẫu nhiên của danh sách đó bằng cách tạo một số nguyên ngẫu nhiên trong khoảng từ 0 đến độ dài của mảng - 1.

Nhược điểm:

  • Bạn cần xây dựng mảng lần đầu tiên bạn muốn tạo một mục.
  • Khi một trong các yếu tố của bạn được cho là có xác suất rất thấp, bạn sẽ có một mảng thực sự lớn, có thể cần rất nhiều bộ nhớ.

Ưu điểm:

  • Khi bạn đã có mảng và muốn rút ra từ nó nhiều lần, thì nó rất nhanh. Chỉ cần một số nguyên ngẫu nhiên và một truy cập mảng.

3
Là một giải pháp lai để tránh nhược điểm thứ hai, bạn có thể chỉ định vị trí cuối cùng là "khác" và xử lý nó thông qua các phương tiện khác, chẳng hạn như phương pháp mảng của Philipp. Do đó, bạn có thể lấp đầy vị trí cuối cùng đó bằng một mảng mang lại 99,9% cơ hội cho thuốc và chỉ có 0,1% cơ hội Epic Scepter of the Apocalypse. Cách tiếp cận hai tầng như vậy tận dụng những lợi thế của cả hai phương pháp.
Cort Ammon

1
Tôi sử dụng một số biến thể của điều này trong dự án của riêng tôi. Những gì tôi làm là tính toán từng mục và trọng lượng, và lưu trữ những thứ đó trong một mảng, [('gold', 1),('sword',4),...]tổng hợp tất cả các trọng số, sau đó cuộn một số ngẫu nhiên từ 0 đến tổng, sau đó lặp lại mảng và tính toán nơi số ngẫu nhiên hạ cánh (nghĩa là a reduce). Hoạt động tốt cho các mảng được cập nhật thường xuyên và không có bộ nhớ chính.

1
@Thebluefish Giải pháp đó được mô tả trong câu trả lời khác của tôi "Giải pháp xác suất được mã hóa mềm"
Philipp

7

Giải pháp xác suất mã hóa cứng

Cách đơn giản nhất để tìm một mục ngẫu nhiên từ bộ sưu tập có trọng số là duyệt qua một chuỗi các câu lệnh if-other, trong đó mỗi câu lệnh if-other tăng có thể, vì cái trước đó không đạt được.

int rand = random(100); //Random number between 1 and 100 (inclusive)
if(rand <= 5) //5% chance
{
    print("You found 10 gold!");
}
else if(rand <= 25) //20% chance
{
    print("You found a sword!");
}
else if(rand <= 70) //45% chance
{
    print("You found a shield!");
}
else if(rand <= 90) //20% chance
{
    print("You found armor!");
}
else //10% chance
{
    print("You found a potion!");
}

Lý do các điều kiện bằng với cơ hội của nó cộng với tất cả các cơ hội có điều kiện trước đó là vì các điều kiện trước đó đã loại bỏ khả năng nó là những vật phẩm đó. Vì vậy, đối với điều kiện của khiên else if(rand <= 70), 70 tương đương với 45% cơ hội của khiên, cộng với 5% cơ hội vàng và 20% cơ hội của thanh kiếm.

Ưu điểm:

  • Dễ dàng để lập trình, bởi vì nó không yêu cầu cấu trúc dữ liệu.

Nhược điểm:

  • Khó duy trì, bởi vì bạn cần duy trì tỷ lệ rơi trong mã của mình. Bạn không thể xác định chúng trong thời gian chạy. Vì vậy, nếu bạn muốn một cái gì đó bằng chứng trong tương lai, bạn nên kiểm tra các câu trả lời khác.

3
Điều này sẽ thực sự gây phiền nhiễu để duy trì. Ví dụ: nếu bạn muốn loại bỏ vàng và làm cho thuốc trở thành vị trí của nó, bạn cần điều chỉnh xác suất của tất cả các vật phẩm giữa chúng.
Alexander - Phục hồi Monica

1
Để tránh vấn đề mà @Alexander đề cập, thay vào đó bạn có thể trừ tỷ lệ hiện tại ở mỗi bước, thay vì thêm nó vào từng điều kiện.
AlexanderJ93

2

Trong C #, bạn có thể sử dụng quét Linq để chạy bộ tích lũy của mình để kiểm tra số ngẫu nhiên trong phạm vi 0 đến 100.0f và .irst () để lấy. Vì vậy, giống như một dòng mã.

Vì vậy, một cái gì đó như:

var item = a.Select(x =>
{
    sum += x.prob;
    if (rand < sum)
        return x.item;
    else
        return null;
 }).FirstOrDefault());

sumlà một số nguyên khởi tạo bằng 0 và alà một danh sách các cấu trúc / bộ dữ liệu thăm dò / mục. randlà một số ngẫu nhiên được tạo trước đó trong phạm vi.

Điều này chỉ đơn giản là tích lũy tổng số trong danh sách các phạm vi cho đến khi vượt quá số ngẫu nhiên được chọn trước đó và trả về mục hoặc null, trong đó null sẽ được trả về nếu phạm vi số ngẫu nhiên (ví dụ 100) nhỏ hơn tổng phạm vi trọng số do nhầm lẫn và số ngẫu nhiên được chọn nằm ngoài phạm vi tổng trọng số.

Tuy nhiên, bạn sẽ nhận thấy rằng các trọng số trong OP rất khớp với phân phối bình thường (Bell Curve). Tôi nghĩ nói chung bạn sẽ không muốn các phạm vi cụ thể, bạn sẽ có xu hướng muốn phân phối giảm bớt xung quanh đường cong hình chuông hoặc chỉ trên một đường cong hàm mũ giảm (ví dụ). Trong trường hợp này, bạn chỉ có thể sử dụng một công thức toán học để tạo một chỉ mục thành một mảng các mục, được sắp xếp theo thứ tự xác suất ưu tiên. Một ví dụ điển hình là CDF trong phân phối bình thường

Cũng là một ví dụ ở đây .

Một ví dụ khác là bạn có thể lấy một giá trị ngẫu nhiên từ 90 độ đến 180 độ để lấy góc phần tư phía dưới bên phải của hình tròn, lấy thành phần x sử dụng cos (r) và sử dụng giá trị đó để lập chỉ mục vào danh sách ưu tiên.

Với các công thức khác nhau, bạn có thể có một cách tiếp cận chung, trong đó bạn chỉ cần nhập danh sách ưu tiên có độ dài bất kỳ (ví dụ N) và ánh xạ kết quả của công thức (ví dụ: cos (x) là 0 đến 1) bằng cách nhân (ví dụ: Ncos (x ) = 0 đến N) để lấy chỉ số.


3
Bạn có thể cho chúng tôi dòng mã này nếu nó chỉ là một dòng không? Tôi không quen thuộc với C # vì vậy tôi không biết ý của bạn là gì.
HEGX64

@ HEGX64 đã thêm nhưng sử dụng điện thoại di động và trình chỉnh sửa không hoạt động. Bạn có thể chỉnh sửa?
Sentinel

4
Bạn có thể thay đổi câu trả lời này để giải thích khái niệm đằng sau nó, chứ không phải là một sự bắt chước cụ thể trong một ngôn ngữ cụ thể?
Raimund Krämer

@ RaimundKrämer Erm, xong chưa?
Sentinel

Downvote mà không giải thích = vô dụng và phản xã hội.
WGroleau

1

Xác suất không cần phải được mã hóa cứng. Các mục và ngưỡng có thể được cùng nhau trong một mảng.

for X in itemsrange loop
  If items (X).threshold < random() then
     Announce (items(X).name)
     Exit loop
  End if
End loop

Bạn vẫn phải tích lũy các ngưỡng, nhưng bạn có thể làm điều đó khi tạo một tệp tham số thay vì mã hóa nó.


3
Bạn có thể giải thích làm thế nào để tính ngưỡng chính xác? Ví dụ: nếu bạn có ba mục với 33% cơ hội mỗi mục, bạn sẽ xây dựng bảng này như thế nào? Vì một ngẫu nhiên mới () được tạo ra mỗi lần, lần đầu tiên sẽ cần 0,3333, lần thứ hai sẽ cần 0,5 và lần cuối sẽ cần 1.0. Hay tôi đã đọc sai thuật toán?
đường ống

Bạn tính toán nó theo cách người khác đã làm trong câu trả lời của họ. Đối với xác suất bằng nhau của các mục X, ngưỡng đầu tiên là 1 / X, thứ hai, 2 / X, v.v.
WGroleau

Làm điều đó cho 3 mục trong thuật toán này sẽ tạo ra các ngưỡng 1/3, 2/3 và 3/3 nhưng xác suất kết quả là 1/3, 4/9 và 2/9 cho mục thứ nhất, thứ hai và thứ ba. Bạn có thực sự có nghĩa là có cuộc gọi đến random()trong vòng lặp?
đường ống

Không, đó chắc chắn là một lỗi. Mỗi kiểm tra cần cùng một số ngẫu nhiên.
WGroleau

0

Tôi đã thực hiện chức năng này: https://github.com/thewheelmaker/GDscript_ WEighted_Random ngay! trong trường hợp của bạn, bạn có thể sử dụng nó như thế này:

on_normal_case([5,20,45,20,10],0)

Nó chỉ cung cấp một số từ 0 đến 4 nhưng bạn có thể đặt nó trong mảng nơi bạn có các mục.

item_array[on_normal_case([5,20,45,20,10],0)]

Hoặc trong chức năng:

item_function(on_normal_case([5,20,45,20,10],0))

Đây là mã. Tôi đã làm nó trên GDscript, bạn có thể, nhưng nó có thể thay đổi ngôn ngữ khác, cũng kiểm tra lỗi logic:

func on_normal_case(arrayy,transformm):
    var random_num=0
    var sum=0
    var summatut=0
    #func sumarrays_inarray(array):
    for i in range(arrayy.size()):
        sum=sum+arrayy[i]
#func no_fixu_random_num(here_range,start_from):
    random_num=randi()%sum+1
#Randomies be pressed down
#first start from zero
    if 0<=random_num and random_num<=arrayy[0]:
        #print(random_num)
        #print(array[0])
        return 0+ transformm
    summatut=summatut+arrayy[0]
    for i in range(arrayy.size()-1):
        #they must pluss together
        #if array[i]<=random_num and random_num<array[i+1]:
        if summatut<random_num and random_num<=summatut+arrayy[i+1]:
            #return i+1+transform
            #print(random_num)
            #print(summatut)
            return i+1+ transformm

        summatut=summatut+arrayy[i+1]
    pass

Nó hoạt động như thế này: on_n normal_case ([50,50], 0) Điều này cho 0 hoặc 1, nó có cùng xác suất cả hai.

on_n normal_case ([50,50], 1) Điều này cho 1 hoặc 2, nó có cùng xác suất cả hai.

on_n normal_case ([20,80], 1) Điều này mang lại 1 hoặc 2, nó có thay đổi lớn hơn để có được hai.

on_n normal_case ([20,80,20,20,30], 1) Điều này cho các số ngẫu nhiên nằm trong phạm vi 1-5 và các số lớn hơn có nhiều khả năng hơn các số nhỏ hơn.

on_n normal_case ([20,80,0,0,20,20,30,0,0,0,0,33], 45) Trò chơi ném xúc xắc này giữa các số 45,46,49,50,51,56 bạn thấy khi ở đó bằng không nó không bao giờ xảy ra.

Vì vậy, hàm này chỉ trả về một số ngẫu nhiên phụ thuộc vào chiều dài của mảng và số biến đổi đó, và số nguyên trong mảng là các trọng số xác suất mà một số có thể xảy ra, trong đó số đó là vị trí trên mảng, số biến đổi kìm.

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.