zoukankan      html  css  js  c++  java
  • 从100万个申请人中选出2万个申请人

    某市要开放一批车牌号,但是申请者众多,只能满足一部分人。

    制定筛选规则如下:

    按照申请日期距离今年年份的距离增加被选中的概率。假设2019年被选中的概率为p,那么2018年的申请人(距离2019年2年)被选中的概率就是2p, 2017年申请的人被选中的概率为3p(距离2019年3年),2016年申请的人被选中的概率为4p(距离2019年4年)。。。以此类推。

    假如总申请人有100万人,本批次拍照发放2万个,请按照上述筛选规则设计算法挑出2万人出来。

    已知这100万人的身份id、对应的申请日期date 。

     z = ((double)rand()/RAND_MAX)*(b-a) + a; //产生区间[a,b]上的随机浮点数

    z = round( (double)rand()/RAND_MAX *(b-a) ) + a; //产生区间[a,b]上的随机整数

    注意:p = rand() % (b-a+1) +a; 并不会等概率的产生[a,b]之间的整数。因为RAND_MAX不一定是(b-a+1)的整数倍。

    思路:

    首先看一下“给定一个长度为N且没有重复元素的数组arr和一个整数M,实现函数等概率随机打印arr中的M个数”的代码。

    第6行是随机生成[0~N-1-i]之间的整数,将其挑出来之后,调用swap函数将其放到后面(“后面”指刚才可选的位置的末尾位置,由于下一次i自增1,所以【0~N-1-i】的末尾位置会前移1,即实现了“选过的不再选” )

     1 vector<int> print(vector<int> arr, int N, int M) { 
     2         int p;
     3         vector<int> ret;
     4         srand((int)time(NULL));
     5         for(int i = 0;i < M;++ i){ 
     6             p = round( (double)rand()/RAND_MAX *(N-i-1) );  
     7             ret.push_back(arr[p]);
     8             swap(arr[p],arr[N - i - 1]);
     9         }
    10         return ret; 
    11     }

    本题和上面的“N个无重复数,等概率的挑M个出来”的题目的不同之处在于,挑的时候要保证“与等待年份相关的概率约束”。

    思路:定义一个一维数组arr,index是申请号,arr[index]是申请人身份的id。

    下面解释如何生成申请号:想象从有记录的那一年开始,每有一个人去申请,都会得到一个顺序号,告知你前面还有多少人在等。每人每年只有一个申请号,这样等待三年的人的手里就积累了三个申请号;同理,等待五年的申请人手里有五个申请号。以此类推。

    这样arr[ 申请号 ]=‘申请人身份id’  组成了一个 长度为N的一个长数组。(N是总共发放的申请号的个数)

    这样就保证了“与等待年份相关的概率约束”。

    但是,这里还有一个问题,就是抽出来的身份id有可能有重复的!那就维持一个“抽出来的身份id”的set,每当抽出来一个身份id使得set集合的大小增1的时候,记录为有效id,否则继续抽,直到抽到有效id。

    (当然每抽一次,就算“失败”了,都把“抽到的申请号”与“可以抽的最后一个申请号”进行交换,这一步是仍然要做。毕竟这一次失败,做交换会保证了下一次成功的概率增加。)

     1 #include <bits/stdc++.h> 
     2 
     3 //personId_date是由 ‘身份id’和 ‘申请日期’组成的表 ;   personId_date的index是personId,对应的值为申请日期 
     4 vector<int> get_arr(vector<int> personId_date ){
     5     vector<int> arr;
     6     int N = 0;
     7     
     8     for(int i=0; i<personId_date.size(); i++){ 
     9         N += abs( personId_date[i] - 2019 ) + 1; 
    10     }
    11     arr.resize(N,0);
    12     
    13     int index = 0;
    14     for(int i=0;i<personId_date.size();i++){
    15         for(int j=0; j<abs( personId_date[i] - 2019 )+1;j++){
    16             arr[index++] = i;  //i是personId 
    17         }        
    18     }
    19     return arr;    
    20 }
    21 
    22 vector<int> print(vector<int> arr, int N, int M) { 
    23     int p;
    24     set<int> personId;
    25     srand((int)time(NULL));
    26     for(int i = 0; personId.size() < M; i++){   
    27         p = round( (double)rand()/RAND_MAX *(N-i-1) ); 
    28         personId.insert( arr[p] );
    29         swap(arr[p],arr[N - i - 1]);              
    30     }
    31     
    32     vector<int> ret;
    33     ret.assign(personId.begin(), personId.end());
    34     return ret; 
    35 }
  • 相关阅读:
    Linux命令--2
    Linux命令--1
    登陆网页模板
    前端笔记 (2.CSS)
    前端笔记 (1.HTML)
    linux 在执行命令过程中,反单引号(`)这个符号代表的意义为何?
    linux 变量
    Linux文件系统中的inode节点详细介绍
    【Ctrl】 + 【Alt】 + 【F1~F6】 和 【Ctrl】 + 【Alt】 + 【T】打开的终端有什么不同?
    快速建站教程
  • 原文地址:https://www.cnblogs.com/liugl7/p/11263984.html
Copyright © 2011-2022 走看看