java实现抽奖概率

该方法构造一个别名表,每次采样时,通过两次rand()来决定采样值,构造的Alias表如下:

Alias table
val 1 2 3 4
alias 3 4 4 -
prob 0.4 0.8 0.6 1.0


根据该表,采样的过程如下,在第一轮我们按 1/N 的概率选择一个采样值,第二轮中根据 alias 表中的概率,看是选择该值还是其别名;如对于val=1,其在第一轮被选中的概率是 1/4=0.25,在第二轮中选择 val=1 而不是其别名(alias=3)的概率是prob=0.4;因此采样值val=1的概率为 0.25*0.4 = 0.1,与PDF符合。读者可自行验证其它几个采样值是否与PDF相符。采用该方法的采样复杂度为O(1)

具体用代码显现 

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
import java.util.Random;
import java.util.TreeMap;
 
 
public final class AliasMethod {
    /* The random number generator used to sample from the distribution. */
    private final Random random;
 
    /* The probability and alias tables. */
    private final int[] alias;
    private final double[] probability;
 
    /**
     * Constructs a new AliasMethod to sample from a discrete distribution and
     * hand back outcomes based on the probability distribution.
     * <p/>
     * Given as input a list of probabilities corresponding to outcomes 0, 1,
     * ..., n - 1, this constructor creates the probability and alias tables
     * needed to efficiently sample from this distribution.
     *
     * @param probabilities The list of probabilities.
     */
    public AliasMethod(List<Double> probabilities) {
        this(probabilities, new Random());
    }
 
    /**
     * Constructs a new AliasMethod to sample from a discrete distribution and
     * hand back outcomes based on the probability distribution.
     * <p/>
     * Given as input a list of probabilities corresponding to outcomes 0, 1,
     * ..., n - 1, along with the random number generator that should be used
     * as the underlying generator, this constructor creates the probability
     * and alias tables needed to efficiently sample from this distribution.
     *
     * @param probabilities The list of probabilities.
     * @param random        The random number generator
     */
    public AliasMethod(List<Double> probabilities, Random random) {
        /* Begin by doing basic structural checks on the inputs. */
        if (probabilities == null || random == null)
            throw new NullPointerException();
        if (probabilities.size() == 0)
            throw new IllegalArgumentException("Probability vector must be nonempty.");
 
        /* Allocate space for the probability and alias tables. */
        probability = new double[probabilities.size()];
        alias = new int[probabilities.size()];
 
        /* Store the underlying generator. */
        this.random = random;
 
        /* Compute the average probability and cache it for later use. */
        final double average = 1.0 / probabilities.size();
 
        /* Make a copy of the probabilities list, since we will be making
         * changes to it.
         */
        probabilities = new ArrayList<Double>(probabilities);
 
        /* Create two stacks to act as worklists as we populate the tables. */
        Deque<Integer> small = new ArrayDeque<Integer>();
        Deque<Integer> large = new ArrayDeque<Integer>();
 
        /* Populate the stacks with the input probabilities. */
        for (int i = 0; i < probabilities.size(); ++i) {
            /* If the probability is below the average probability, then we add
             * it to the small list; otherwise we add it to the large list.
             */
            if (probabilities.get(i) >= average)
                large.add(i);
            else
                small.add(i);
        }
 
        /* As a note: in the mathematical specification of the algorithm, we
         * will always exhaust the small list before the big list.  However,
         * due to floating point inaccuracies, this is not necessarily true.
         * Consequently, this inner loop (which tries to pair small and large
         * elements) will have to check that both lists aren't empty.
         */
        while (!small.isEmpty() && !large.isEmpty()) {
            /* Get the index of the small and the large probabilities. */
            int less = small.removeLast();
            int more = large.removeLast();
 
            /* These probabilities have not yet been scaled up to be such that
             * 1/n is given weight 1.0.  We do this here instead.
             */
            probability[less] = probabilities.get(less) * probabilities.size();
            alias[less] = more;
 
            /* Decrease the probability of the larger one by the appropriate
             * amount.
             */
            probabilities.set(more,
                    (probabilities.get(more) + probabilities.get(less)) - average);
 
            /* If the new probability is less than the average, add it into the
             * small list; otherwise add it to the large list.
             */
            if (probabilities.get(more) >= 1.0 / probabilities.size())
                large.add(more);
            else
                small.add(more);
        }
 
        /* At this point, everything is in one list, which means that the
         * remaining probabilities should all be 1/n.  Based on this, set them
         * appropriately.  Due to numerical issues, we can't be sure which
         * stack will hold the entries, so we empty both.
         */
        while (!small.isEmpty())
            probability[small.removeLast()] = 1.0;
        while (!large.isEmpty())
            probability[large.removeLast()] = 1.0;
    }
 
    /**
     * Samples a value from the underlying distribution.
     *
     * @return A random value sampled from the underlying distribution.
     */
    public int next() {
        /* Generate a fair die roll to determine which column to inspect. */
        int column = random.nextInt(probability.length);
 
        /* Generate a biased coin toss to determine which option to pick. */
        boolean coinToss = random.nextDouble() < probability[column];
 
        /* Based on the outcome, return either the column or its alias. */
       /* Log.i("1234","column="+column);
        Log.i("1234","coinToss="+coinToss);
        Log.i("1234","alias[column]="+coinToss);*/
        return coinToss ? column : alias[column];
    }
 
    private static int o1=1;
    private static int o2=2;
    private static int o3=3;
    private static int o4=10;
    private static int o5=20;
    private static int o6=30;
    private static int o7=40;
    private static int o8=50;
    
    public static String outPrize(int num){
    	TreeMap<String, Double> map = new TreeMap<String, Double>();
        map.put("一等奖", 0.0001*num*2);
        map.put("二等奖", 0.001*num);
        map.put("三等奖", 0.005);
        map.put("四等奖", 0.01);
        map.put("五等奖", 0.04);
        map.put("六等奖", 0.1);
        map.put("七等奖", 0.2);
        map.put("八等奖", 0.35);
        map.put("未中奖", 0.29);
 
        List<Double> list = new ArrayList<Double>(map.values());
        List<String> gifts = new ArrayList<String>(map.keySet());
 
        AliasMethod method = new AliasMethod(list);
 

    	String val=gifts.get(method.next());
    	if(val.equals("一等奖")){
    		o1=o1-1;
    	}
    	if(val.equals("二等奖")){
    		o2=o2-1;
    	}
    	if(val.equals("三等奖")){
    		o3=o3-1;
    	}
    	if(val.equals("四等奖")){
    		o4=o4-1;
    	}
    	if(val.equals("五等奖")){
    		o5=o5-1;
    	}
    	if(val.equals("六等奖")){
    		o6=o6-1;
    	}
    	if(val.equals("七等奖")){
    		o7=o7-1;
    	}
    	if(val.equals("八等奖")){
    		o8=o8-1;
    	}
        
        /*Map<String, AtomicInteger> resultMap = new HashMap<String, AtomicInteger>();
        for (int i = 0; i < 5000; i++) {
            int index = method.next();
            String key = gifts.get(index);
            if (!resultMap.containsKey(key)) {
                resultMap.put(key, new AtomicInteger());
            }
            resultMap.get(key).incrementAndGet();
        }
        Integer timestampTwo=(int) (0+Math.random()*100);
        for (String key : resultMap.keySet()) {
            System.out.println(key + "==" + resultMap.get(key));
            
            if(timestampTwo==resultMap.get(key).intValue()){
            	System.out.println("哎呀    "+key);
            }
        }*/
    	return val;
    }
    
    public static void main(String[] args) throws Exception {
    	int num = 1;
    	for(int i=0;i<10;i++){
    		if(i%100==0){
    			num=num+1;
    		}
        	System.out.println("第"+i+"次--哎呀 "+outPrize(num));
    	}
    	System.out.println("一等奖剩余"+o1);
    	System.out.println("二等奖剩余"+o2);
    	System.out.println("三等奖剩余"+o3);
    	System.out.println("四等奖剩余"+o4);
    	System.out.println("五等奖剩余"+o5);
    	System.out.println("六等奖剩余"+o6);
    	System.out.println("七等奖剩余"+o7);
    	System.out.println("八等奖剩余"+o8);
    }
}

参考地址:

 http://blog.csdn.net/haolexiao/article/details/65157026

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值