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