您的位置:首页 > 编程语言

编程珠玑: 12章 取样问题 12.1程序的输入包含两个整数m和n,其中m<n。输出是0~n-1范围内m个随机整数的有序列表,不允许重复-------解题总结

2017-01-25 09:22 423 查看
#include <iostream>
#include <stdio.h>
#include <vector>
#include <algorithm>

using namespace std;
/*
问题:程序的输入包含两个整数m和n,其中m<n。输出是0~n-1范围内m个随机整数的有序列表,不允许重复。从概率的角度说,我们希望得到没有重复的有序选择,其中
每个选择出现的概率相等。
分析:这个感觉是蓄水池抽样问题。先设置0~m-1为前m个随机整数,然后对于i从m开始,生成随机数k,如果k < m - 1,就将i和k进行调换。
下面证明该程序的等概率:假设从1~n个数中随机选择m个不同的数,且概率相等。
假设当前为第i+1个数,则第i+1个数出现在蓄水池的概率为m/(i+1),现在证明前面i个数中出现在蓄水池的概率也为m(i+1)【先以简单的部分作为论点,论述
前面较难的条件成立】
证明:前面i个数出现蓄水池的概率=第i+1次选择前出现在蓄水池的概率 * 第i+1次选择不被替换的概率
= m/i  * (1 - 第i+1次选择被替换的概率)
= m/i * (1 - 1/(i+1) = m/(i+1)

关键:
1 证明前面i个数出现在蓄水池的概率和第i+1个数出现在蓄水池的概率相同
2 蓄水池步骤:1 将原数组A[1...m]赋值给新数组B[1...m],对于x属于m+1~n,随机得到一个数k,若k <= m ,就交换B[x]和B[k]

输入:
10(随机选择的数) 100(整数范围n)
输出:
10个不同元素组成的有序列表
*/

int randRange(int min , int max)
{
if(min > max)
{
int temp = min;
min = max;
max = temp;
}
return ( rand() % (max - min + 1) + min );
}

//生成0~n-1中m个随机选择的不重复的数组成的有序列表
vector<int> getRandomVector(int m , int n)
{
vector<int> results;
//前面m个数的直接拷贝
for(int i = 0 ; i < m ; i++)
{
results.push_back(i);
}

//后面的随机替换
for(int i = m ; i < n ; i++)
{
int k = randRange(0 , n - 1);
if(k <= m - 1)
{
results.at(k) = i;
}
}

//替换后的结果注意要排序
sort(results.begin() , results.end());
return results;
}

void print(vector<int>& results)
{
if(results.empty())
{
cout << "no result" << endl;
return;
}
int size = results.size();
for(int i = 0 ; i < size; i++)
{
cout << results.at(i) << " ";
}
cout << endl;
}

void process()
{
int m , n;
vector<int> results;
while(cin >> m >> n)
{
results = getRandomVector(m , n);
print(results);
}
}

int main(int argc , char* argv[])
{
process();
getchar();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐