水一篇算法分析与设计的实验报告
就是说咱也不知道为什么算法课那么水,可能这就是RUC吧
无放回采样
题意简述
实现无放回采样算法,输入为一个数组和正整数k,算法对数组进行操作,前k位为采样结果。
算法基本思路
使用c++中的vector容器,定义可迭代的数组,从而便于输入未知长度的数组;
在生成随机数的时候,使用c++中自带的rand()函数,对该函数取模,模的数字为当前数组的长度,从而实现生成一个范围在数组长度内的整数。
在采样过程中,通过生成的随机数对数组进行索引,并删除对应的数据,将被删除的数组元素加入采样结果中。然后根据输入的k的大小进行下一次迭代
算法正确性证明
略
算法复杂度
时间复杂度为,空间复杂度为
代码设计以及基本框架
int main()
{
vector<int> A;
long long int number = 0;
vector<int>numbers;
cout<<"请输入数组";
while(1)
{
cin>>number;
A.push_back(number);//每输入一个数字就放在数组最后
if(cin.get()=='\n')break;
}
long long int len = A.size();//数组长度len
cout<<"您输入的数组是:";
for(int i=0;i<len;i++)
{
cout<<A[i]<<' ';
}
cout<<"请输入要采样的个数:";
long long int k = 0,i=0;
cin >>k;
long long int random = 0;
for(i=0;i<k;i++)
{
std::srand(std::time(0));
random = std::rand()%A.size();
std::cout<<"删除当前数组中第"<<random<<"个数字";
numbers.push_back(A[random-1]);
A.erase(A.begin()+random-1);
cout<<"现在的数组是:";
for(int i=0;i<A.size();i++)
{
cout<<A[i]<<' ';
}
cout<<endl;
}
cout<<"您采样出的数组为:";
for(int j = 0;j<numbers.size();j++)
{
cout<<numbers[j]<<" ";
}
return 0;
}
运行结果示例
蒙特卡洛模拟圆周率
题意简述
实现pi的Monte Carlo算法,假设我们要求误差小于0.0001。在不使用pi真实值的前提下,如何设计算法的停止条件。
算法基本思路
使用蒙特卡洛对圆周率进行模拟,我们随机地生成点,通过计算落在半径为1的圆内的数量与落在2*2的正方形中的总数量的比值。
由于题目要求不能使用真实值,我们模拟计算pi的结果。
利用
可以得到:,
于是我们通过模拟值对圆周率进行估计,利用估计值蒙特卡洛估计值,|估计值-蒙特卡洛估计值|<1e-4 作为停止条件
算法正确性证明
只要我们设置足够的迭代次数使得pi的估计值尽可能准确,该算法得到的结果与真实值相差必然小于0.0001
代码设计以及基本框架
int main()
{
std::cout.setf(std::ios_base::fixed, std::ios_base::floatfield);
double pi;
unsigned long long int num;
num = 1000000;
for(unsigned long long int i = 0;i<num;i++)
{
pi += pow(-1,i)*1/(2*i+1);
}
pi = 4.0*pi;
// cout<<pi;
double guji=0;
double x = 0;
double y = 0;
long numCount = 0;
long sum = 0;
srand((unsigned)time(NULL));
// cout<<1e-4<<endl;
while(abs(guji-pi)>1e-6)
{
sum++;
x = rand()/(double)(RAND_MAX);
y = rand()/(double)(RAND_MAX);
if((x*x)+(y*y)<1)
numCount++;
guji = 4.0*numCount/sum;
}
cout<<"迭代次数"<<sum<<endl;
// cout<<guji;
cout<<guji;
return 0;
}
运行结果示例
思路2
尽可能增大迭代次数,通过数学计算可以得知当迭代次数达到一定值的时候结果与真实值的差距小于0.0001的概率接近于1。