从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 }

 

posted on 2019-07-29 15:09  逸阳  阅读(195)  评论(0编辑  收藏  举报

导航