小洛机器人和你玩猜数游戏!小洛随机选择并默默记下一个1~100的整数,你需要不断猜测这个数字是什么并输入验证。如果你输入的数字比小洛选择的数字小,小洛会输出“Too small”;如果比小洛选择的数字大,小洛输出“TOO large”;如果刚好猜对,小洛输出“You are right!!”。如果一次没有猜中,则继续猜,直到猜中为止。
这个猜数游戏是一个经典的二分查找算法的应用实例,其中小洛机器人代表程序中的算法部分,而你代表与程序交互的用户。
程序的基本逻辑流程:
1、初始化阶段:小洛机器人在1到100之间随机选择一个整数作为答案。
2、用户输入:用户输入一个猜测的数字。
3、比较阶段:
- 如果用户猜的数字小于小洛机器人选择的数字,小洛机器人输出 "Too small"。
- 如果用户猜的数字大于小洛机器人选择的数字,小洛机器人输出 "TOO large"。
- 如果用户猜的数字正好等于小洛机器人选择的数字,小洛机器人输出 "You are right!!"。
- 循环判断:如果用户没有猜中数字,程序会返回到用户输入阶段,让用户继续猜测,直到猜中为止。
4、结束条件:当用户猜中数字时,程序结束。
这个程序可以用伪代码表示如下:
function play_guessing_game
secret_number = random_number_between(1, 100) // 小洛随机选择数字
while true
guess = get_user_input() // 用户输入猜测数字
if guess < secret_number
print "Too small"
else if guess > secret_number
print "TOO large"
else
print "You are right!!"
break // 猜中数字,退出循环
end if
end while
end function
在这个猜数游戏中,通常选择 do-while 循环而不是其他类型的循环(如 while 循环或 for 循环)的原因是:
- 保证至少执行一次:do-while 循环至少会执行一次循环体内的代码块,无论条件是否为真。这对于猜数游戏来说是必要的,因为玩家至少需要一次猜测的机会。
- 在循环结束后检查条件:do-while 循环会在执行循环体的代码之后检查条件。这意味着即使在第一次猜测后玩家就猜对了数字,循环依然会进行一次猜测,然后检查条件并退出。
如何让计算机产生一个随机数呢?
可以使用rand()函数来产生一个0~RAND_MAX的整数,其中RAND_MAX是一个常量,其值与编译系统有关,而且别忘了加上头文件cstdlib。
可以使用rand()%a产生一个0~a-1的随机数。如果想产生一个a到b的随机数,可以使用rand()%(b-a+1)+a。
rand()生成的是“伪随机数”,因此每次执行前都要“喂给它”不同的初始值(srand()函数作为随机数种子,这样才能生成不同的随机数)。喂给它当前时间就是一个比较好的选择。
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
int main(){
int ans,guess;
srand(time(0));
ans=rand()%100+1;
do{
cin>>guess;
if(guess<ans)
cout<<"Too small"<<endl;
else if(guess>ans)
cout<<"Too large"<<endl;
}while(guess!=ans);
cout<<"You are right!!"<<endl;
}
rand()%a看起来可以生成一个0到a-1的随机数,但是每个数字并不是等可能的。假设RNAD_MAX是32767,取0~99的随机数时,抽到0~67的可能要比剩下的数字大一点(想一想,为什么)。如果RAND_MAX远大于a时,影响并不大。请考虑一种等可能的生成区间随机数方式(可能需要多次抽取)
rand() % a 这种生成随机数的方法确实可以生成一个 0 到 a-1 范围内的整数,但是它可能不会是完全等概率的。这主要是因为 rand() 函数生成的随机数分布可能不是完全均匀的,特别是在模运算中,某些数字可能比其他数字出现的概率稍高。
当使用 rand() % a 时,如果 RAND_MAX 和 a 之间存在一定的数学关系,比如 a 是 100,而 RAND_MAX 是 32767,那么理论上每个数字出现的概率应该是相等的。但实际上,由于 rand() 函数生成的随机数可能存在轻微的偏差,以及模运算本身的数学特性,某些数字可能会比其他数字出现得更频繁。
具体来说,如果 RAND_MAX 除以 a 有余数,那么在取模运算中,0 到 (RAND_MAX % a - 1) 范围内的数字出现的概率会略高于其他数字。这是因为当 RAND_MAX 被 a 除尽时,余数范围内的数字会多出一些可能的随机数映射。例如,如果 RAND_MAX 是 32767,当 a 是 100 时,RAND_MAX % 100 的结果是 67,这意味着在 0 到 67 之间的数字有更多的机会映射到 rand() % 100 的结果中。
为了获得更均匀分布的随机数,可以采取以下方法之一:
1、使用更好的随机数生成器:C++11 中的 <random> 库提供了多种高质量的随机数生成器,例如 std::mt19937,它是基于 Mersenne Twister 算法。
2、调整随机数生成策略:使用不同的方法来生成随机数,例如先生成一个更大的范围内的随机数,然后通过适当的缩放和偏移来得到所需的范围。
3、后处理随机数序列:对生成的随机数序列进行后处理,例如通过随机打乱序列来减少任何可能的偏差。
4、使用舍入:如果需要更均匀的分布,可以先生成一个更大的范围的随机数,然后通过舍入到最近的整数来获得所需范围内的随机数。
使用 C++11 的 <random> 库可以很容易地实现这些改进,从而获得更高质量的随机数。