• 概率算法总结


    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace Leetcode.概率算法
    {
        class Probability
        {
            static void Main(string[] args)
            {
                int[] arry = new int[100];
                int[] weight = new int[100];
                Random radom = new Random();
                for (int i = 0; i < 100; i++)
                {
                    arry[i] = i;
                    weight[i] = radom.Next(100);
                }
    
                while (true)
                {
                    int result = WeightSamp(arry,weight);
                    Console.WriteLine(result);
                    Thread.Sleep(100);
                }
            }
            //问题1:假设一个随机数发生器rand7均匀产生1到7之间的随机整数,如何构造rand10,均匀产生1-10之间的随机整数?
            //解决方法一:1-7之间有4个奇数,3个偶数,我们扔掉一个奇数,比如7,这样剩余3个奇数,
            //3个偶数产生的概率相同——我们构造了一个0-1整数的均匀产生器,用它产生4个bit,对应表示整数0..15, 保留1..10就可以了
            public static int Arand10()
            {
                Random radom = new Random();
                int result = 0;
                int i = 0;//循环计数使用的
                int cur = radom.Next(8);
                while (cur != 7)
                {
                    if (cur % 2 == 0)
                    {
                        result = (result << 1) | 0;
                    }
                    else
                    {
                        result = (result << 1) | 1;
                    }
                    cur = radom.Next(8);
                    i++;
                    if (i == 4)
                    {
                        if (result <= 10)//result<10丢掉
                            break;
                        else
                        {
                            result = 0;
                            i = 0;
                        }
                    }
                }
                return result;
            }
    
            //解决方法二:我们把1-7减去1,变为0-6。产生一个两位的七进制数,对应0-48,
            //我们把40-48扔掉(因为这只有9个数),其余按照个位数字分类,0-9对应我们要的1-10
            public static int Brand10()
            {
                Random radom = new Random();
                int cur1 = radom.Next(8);
                int cur2 = radom.Next(8);
                int result = cur1 * 7 + cur2;
                while (result > 40)
                {
                    cur1 = radom.Next(8);
                    cur2 = radom.Next(8);
                    result = cur1 * 7 + cur2;
                }
                result = result % 10 + 1;
                return result;
            }
    
            //问题二:不均匀随机数发生器构造均匀
            //一个随机数发生器,不均匀,以概率p产生0,以(1-p)产生1, (0<p<1),构造一个均匀的随机数发生器 
            //分析:产生两次,(0,1)的概率与(1,0)的概率相同都是p * (1 – p)。
            //现在想要构造1-10之间的随机数,则可以使用4位,当随机数产生(1,0)的时候产生1,当随机数产生(0,1)的时候产生0即可
    
    
            //问题三:水库(Reservoir)采样
            //题目描述:流入若干个对象(整数),事先不知道个数。如何随机取出k个 (k小于总数)?
            //解决方法:用一个数组a保存k个数 a[0..k -1]
            //对于第i个元素(i = 1,2,…),如果i <= k: 则a[i -1]存放这个元素
            //否则:产生随机数x = rand() % i
            //若x < k,则用a[x]存放这个元素(扔掉之前的元素)
            //简单证明:假设目前已经流入n > k个元素
            //第i( i <= k)个元素被选中的可能性,1 * k / (k + 1) * (k + 1) / (k + 2) *…*(n -1) / n = k / n(第一次被选中的概率*以后不被换掉的概率)
            //第i (i > k)个元素被选中的可能性,k / i * i / (i + 1) * (i + 1) / (i + 2) *…* (n – 1) / n = k / n(第一次选中的概率*以后不被换掉的概率)
            public static int[] Reservoir(int k)
            {
                int[] arry = new int[k];
                Flow flow = new Flow();
                int i = 0;
                while (!flow.IsEnd())
                {
                    int cur = flow.GetNext();
                    if (i < k)
                    {
                        arry[i] = cur;
                        i++;
                    }
                    else
                    {
                        int random = (new Random().Next()) % i;
                        if (random < k)
                        {
                            arry[random] = cur;
                            i++;
                        }
                    }
                }
                return arry;
            }
    
            //问题四:用数组a[0..n -1]随机产生一个全排列,算法导论上的题目,上面有证明
            public static int[] RndomShuffle(int n)
            {
                int[] arry = new int[n];
                for (int i = 0; i < n; i++)
                {
                    arry[i] = i;
                }
    
                for (int i = 0; i < n; i++)
                {
                    int index = new Random().Next() % (n - i) + i;
                    Swap(arry, index, i);
                }
                return arry;
            }
    
            public static void Swap(int[] arry, int index1, int index2)
            {
                int temp = arry[index1];
                arry[index1] = arry[index2];
                arry[index2] = temp;
            }
    
    
            //问题5:带权采样问题
            //给定n种元素,再给定n个权值,按权值比例随机抽样一个元素。为了方便我们可以假设权值全是整数
            //比较好的解法:先按1/m的概率随机选择一种元素
            //再产生随机数根据权值决定能否选择这种元素,如果能则选取它并结束,否则返回(1)
            //Pi1 = Wi / Wtot  或Pi2 =Wi  / Wmax 无关紧要(正比于Wi)
            //证明:
            public static int WeightSamp(int[] arry, int[] weight)
            {
                int result = 0;
                int length = arry.Length;
                int max = weight.Max();//找出最大的权重
                Random radom = new Random();
                while (true)
                {
                    int cur1 = radom.Next(length);//随机选取一个数
                    int cur2 = radom.Next(max + 1);
                    if (weight[cur1] <= cur2)
                    {
                        result = cur1;
                        break;
                    }
                }
                return result;
            }
        }
    
        //模拟数据流
        public class Flow
        {
            private int[] arry;
            private int cur = -1;
    
            public Flow()
            {
                arry = new int[100];
                for (int i = 0; i < 100; i++)
                {
                    arry[i] = i;
                }
            }
    
            public int GetNext()
            {
                cur++;
                return arry[cur];
            }
    
            public bool IsEnd()
            {
                if (cur < 99)
                    return false;
                else
                    return true;
            }
        }
    }

    最后一个问题的证明如图:

  • 相关阅读:
    偷窃转基因玉米种子引发中美打农业官司
    关于PreferenceActivity的使用和一些问题的解决(自己定义Title和取值)
    大写中文数字-財务
    【leetcode】LRU
    【AC大牛陈鸿的ACM总结贴】【ID AekdyCoin】人家当初也一样是菜鸟
    android面试题 不单单为了面试也是一次非常好的学习
    存储系统的实现-探析存储的机制和原理
    unity3d脚本编程
    ubuntu12.04 安装配置jdk1.7
    Android中一个类实现的接口数不能超过七个
  • 原文地址:https://www.cnblogs.com/FJuly/p/4731254.html
Copyright © 2020-2023  润新知