Алгоритмы: Как реализовать случайный выбор с весами?

алгоритм
Алгоритмы: Как реализовать случайный выбор с весами?

Введение: Мы все знаем, что многие компании обычно проводят оценку эффективности в середине/конце года.В данном случае мы предполагаем, что оценки эффективности являются A, B, C и D от высокого к низкому. Затем, поскольку результаты служебной аттестации напрямую связаны с продвижением сотрудника по службе и повышением заработной платы, а также со стандартами премирования в конце года (например, в классе А выплачивается месячная заработная плата в марте; в классе В выплачивается месячная заработная плата за 2,5 месяца; в классе С выплачивается месячная заработная плата за февраль. ; класс D не имеет премий в конце года и рискует быть уволенным), поэтому руководители компании установили негласное правило для оценки эффективности и прямо и тайно разделили пропорцию каждого уровня производительности заранее (например: A 10 %; Б 20%; С 65%; Д 5%). Итак, теперь вопрос в том, что в проектной команде, за исключением очень немногих выдающихся сотрудников, ту же работу выполняют другие, и у них будет свое мнение о том, кто выше, а кто ниже. время, как вы должны выполнить работу?Может ли оценка максимально сбалансировать мнения руководителей и членов команды?

Да, раз выбрать не просто, то пишите код для реализации алгоритма взвешенного случайного выбора.Если повезет, то можно получить хорошую производительность, а если не повезет, то низкую производительность. Алгоритм открытый и прозрачный, производительность зависит от удачи, предположительно члены команды могут его принять, наверное (◔◡◔)

Реализация алгоритма

Прежде чем писать конкретный код, мы можем подумать о том, как реализовать этот взвешенный случайный выбор.

Возьмем приведенное выше введение в качестве примера: вероятность появления A составляет 10%, вероятность появления B составляет 20%, вероятность появления C составляет 65%, а вероятность появления D составляет 5%. Мы преобразуем это в прогрессивное значение вероятности, которое выглядит следующим образом:

带权重的随机选择

Идея алгоритма прояснилась, а логику алгоритма написать легко.Ниже я приведу пример написанного мною алгоритма для справки.

import org.junit.Test;

import java.math.BigDecimal;
import java.text.MessageFormat;
import java.util.Random;

/**
 * 带权重的随机选择
 *
 * @author zifangsky
 * @date 2020/5/15
 * @since 1.0.0
 */
public class Problem_004_Weight_Random {

    /**
     * 测试代码
     */
    @Test
    public void testMethods(){
        Item[] items = new Item[]{new Item("A", 0.1),
                new Item("B", 0.2),
                new Item("C", 0.65),
                new Item("D", 0.05),};

        WeightRandom weightRandom = new WeightRandom(items);
        for(int i = 0; i < 10; i++){
            System.out.println(MessageFormat.format("员工{0}的绩效得分:{1}",
                    (i + 1),weightRandom.nextItem()));
        }
    }


    /**
     * 带权重的随机选择
     */
    static class WeightRandom{
        /**
         * 选项数组
         */
        private Item[] options;

        /**
         * 权重的临界值
         */
        private BigDecimal[] criticalWeight;

        private Random rnd;

        public WeightRandom(Item[] options) {
            if(options == null || options.length < 1){
                throw new IllegalArgumentException("选项数组存在异常!");
            }
            this.options = options;
            this.rnd = new Random();
            //初始化
            this.init();
        }

        /**
         * 随机函数
         */
        public String nextItem(){
            double randomValue = this.rnd.nextDouble();
            //查找随机值所在区间
            int index = this.searchIndex(randomValue);

            return this.options[index].getName();
        }

        /**
         * 查找随机值所在区间
         */
        private int searchIndex(double randomValue){
            BigDecimal rndValue = new BigDecimal(randomValue);
            int high = this.criticalWeight.length - 1;
            int low = 0;
            int median = (high + low) / 2;

            BigDecimal medianValue = null;
            while (median != low && median != high){
                medianValue = this.criticalWeight[median];

                if(rndValue.compareTo(medianValue) == 0){
                    return median;
                }else if(rndValue.compareTo(medianValue) > 0){
                    low = median;
                    median = (high + low) / 2;
                }else{
                    high = median;
                    median = (high + low) / 2;
                }
            }

            return median;
        }

        /**
         * 初始化
         */
        private void init(){
            //总权重
            BigDecimal sumWeights = BigDecimal.ZERO;
            //权重的临界值
            this.criticalWeight = new BigDecimal[this.options.length + 1];

            //1. 计算总权重
            for(Item item : this.options){
                sumWeights = sumWeights.add(new BigDecimal(item.getWeight()));
            }

            //2. 计算每个选项的临界值
            BigDecimal tmpSum = BigDecimal.ZERO;
            this.criticalWeight[0] = tmpSum;
            for(int i = 0; i < this.options.length; i++){
                tmpSum = tmpSum.add(new BigDecimal(this.options[i].getWeight()));
                this.criticalWeight[i + 1] = tmpSum.divide(sumWeights, 2, BigDecimal.ROUND_HALF_UP);
            }
        }
    }

    /**
     * 需要随机的item
     */
    static class Item{
        /**
         * 名称
         */
        private String name;
        /**
         * 权重
         */
        private double weight;

        public Item(String name, double weight) {
            this.name = name;
            this.weight = weight;
        }

        public String getName() {
            return name;
        }

        public double getWeight() {
            return weight;
        }
    }

}

Вывод примера кода выглядит следующим образом:

员工1的绩效得分:C
员工2的绩效得分:B
员工3的绩效得分:B
员工4的绩效得分:C
员工5的绩效得分:C
员工6的绩效得分:B
员工7的绩效得分:C
员工8的绩效得分:C
员工9的绩效得分:B
员工10的绩效得分:C