第1关:硬币实验
任务描述 相关知识 随机数 编程要求 测试说明
任务描述
本关任务:计算机产生的伪随机数来模拟抛硬币试验。
相关知识
为了完成本关任务,你需要掌握:1.如何获取数组的长度,2.如何遍历数组。
随机数
随机数在随机化算法设计中扮演着十分重要的角色。
在现实计算机上无法产生真正的随机数,因此在随机化算法中使用的随机数都是一定程度上随机的,即伪随机数。
用计算机产生的伪随机数来模拟抛硬币试验。
假设抛10次硬币,每次抛硬币得到正面和反面是随机的。拋10次硬币构成一个事件。
调用Random(2)返回一个二值结果。
在主程序中反复调用函数TossCoins模拟拋10次硬币这一事件50000次。
用headi记录这50000次模拟恰好得到i次正面的刺手。最终输出模拟抛硬币事件得到的正面事件的概率图。
编程要求
根据提示,在右侧编辑器补充代码。
测试说明
RandomNumber.h 函数已经写好,可以点击查看。
平台会对你编写的代码进行测试:
例如:
输入:
10
50000
输出:
0 *
1 *
2 *
3 *
4 *
5 *
6 *
7 *
8 *
9 *
10 *`
#include "RandomNumber.h"
#include <iostream>
using namespace std;
int TossCoins(int numberCoins);
int main()
{
//模拟随机抛硬币事件
int NCOINS;
long NTOSSES;
cin >>NCOINS;
cin >>NTOSSES;
//heads[i]是得到i次正面的次数
long i,heads[NCOINS+1];
int j,position;
//初始化数组heads
for(int j=0; j<NCOINS+1;j++)
{
heads[j] = 0;
}
//重复50,000次模拟事件
for(int i=0; i<NTOSSES; i++)
{
heads[TossCoins(NCOINS)]++;
}
//输出频率图
for(int i=0; i<=NCOINS; i++)
{
position = int(float(heads[i])/NTOSSES*72);
cout<<i<<" ";
for(int j=0; j<position-1; j++)
{
cout<<" ";
}
cout<<"*"<<endl;
}
return 0;
}
int TossCoins(int numberCoins)
{
//随机抛硬币
static RandomNumber coinToss(1);
int i,tosses = 0;
for(int i=0; i<numberCoins; i++)
{
//Random(2) = 1表示正面
tosses += coinToss.Random(2);
}
return tosses;
}
第2关:用随机投点法求圆周率
任务描述
相关知识
编程要求
测试说明
任务描述
本关任务:编写一个程序,利用随机投点法计算圆周率
相关知识
编程要求
根据提示,在右侧编辑器补充代码。
测试说明
平台会对你编写的代码进行测试:
输入:
100
输出:
n1=100
pi=3.12
开始你的任务吧,祝你成功!
//随机化算法 用随机投点法计算π值
#include "RandomNumber.h"
#include <iostream>
using namespace std;
double Darts(int n);
int main()
{
int n1;
cin>> n1;
cout<<"n1="<<n1<<"\npi="<<Darts(n1)<<endl;
return 0;
}
//用随机投点法计算π值
double Darts(int n)
{
static RandomNumber dart(1);
int k = 0;
for(int i=1; i<=n; i++)
{
double x = dart.fRandom();
double y = dart.fRandom();
if((x*x + y*y)<=1)
{
k++;
}
}
return 4*k/double(n);
}
第3关:解非线性方程组
任务描述 相关知识 编程要求 测试说明
任务描述
本关任务:编写程序求线性方程组。
相关知识
求解下面的非线性方程组
编程要求
求一个简单的二维线性方程组:
x1-x2=fx1
x1+x2=fx2
根据提示,在右侧编辑器补充代码。
测试说明
平台会对你编写的代码进行测试:
例如:
输入:
1
3
输出:
The original equations are:
x1-x2=1
x1+x2=3
The roots are:
x1=2.02104 x2=1.01445
开始你的任务吧,祝你成功!
//随机化算法 解线性方程组
#include "RandomNumber.h"
#include <iostream>
using namespace std;
bool NonLinear(double *x0,double *dx0,double *x,double *fx,double a0,
double epsilon,double k,int n,int Steps,int M);
double f(double *x,double *fx);
int main()
{
double *x0, //根初值
*x, //根
*dx0, //增量初值
*fx, // 函数值
a0 = 0.0001, //步长
epsilon = 0.01, //精度
k = 1.1; //步长变参
int n = 2, //方程个数
Steps = 10000, //执行次数
M = 1000; //失败次数
x0 = new double[n+1];
dx0 = new double[n+1];
x = new double[n+1];
fx = new double[n+1];
cin >> fx[1];
cin >> fx[2];
//根初值
x0[1] = 0.0;
x0[2] = 0.0;
//增量初值
dx0[1] = 0.01;
dx0[2] = 0.01;
cout<<"The original equations are:"<<endl;
cout<<"x1-x2="<<fx[1]<<endl;
cout<<"x1+x2="<<fx[2]<<endl;
cout<<"The roots are:"<<endl;
bool flag = NonLinear(x0,dx0,x,fx,a0,epsilon,k,n,Steps,M);
while(!flag)
{
flag = NonLinear(x0,dx0,x,fx,a0,epsilon,k,n,Steps,M);
}
for(int i=1; i<=n; i++)
{
cout<<"x"<<i<<"="<<x[i]<<" ";
}
cout<<endl;
return 0;
}
//解非线性方程组的随机化算法
bool NonLinear(double *x0,double *dx0,double *x,double *fx,double a0,
double epsilon,double k,int n,int Steps,int M)
{
static RandomNumber rnd(1);
bool success; //搜索成功标志
double *dx,*r;
dx = new double[n+1]; //步进增量向量
r = new double[n+1]; //搜索方向向量
int mm = 0; //当前搜索失败次数
int j = 0; //迭代次数
double a = a0; //步长因子
for(int i=1; i<=n; i++)
{
x[i] = x0[i];
dx[i] = dx0[i];
}
double fy = f(x,fx); //计算目标函数值
double min = fy; //当前最优值
while(j<Steps)
{
//(1)计算随机搜索步长
if(fy<min)//搜索成功
{
min = fy;
a *= k;
success = true;
}
else//搜索失败
{
mm++;
if(mm>M)
{
a /= k;
}
success = false;
}
if(min<epsilon)
{
break;
}
//(2)计算随机搜索方向和增量
for(int i=1; i<=n; i++)
{
r[i] = 2.0 * rnd.fRandom()-1;
}
if(success)
{
for(int i=1; i<=n; i++)
{
dx[i] = a * r[i];
}
}
else
{
for(int i=1; i<=n; i++)
{
dx[i] = a * r[i] - dx[i];
}
}
//(3)计算随机搜索点
for(int i=1; i<=n; i++)
{
x[i] += dx[i];
}
//(4)计算目标函数值
fy = f(x,fx);
j++;
}
if(fy<=epsilon)
{
return true;
}
else
{
return false;
}
}
double f(double *x, double* fx)
{
return (x[1]-x[2]-fx[1])*(x[1]-x[2]-fx[1])
+(x[1]+x[2]-fx[2])*(x[1]+x[2]-fx[2]);
}