问题描述:
M个人围成一圈报数,数到N(1<N<10)的倍数或包含N这个数字时出圈,问剩下的最后一个人在原来的位置是多少?(当然约瑟夫问题原文叙述并不是这样,这里这个出圈问题和其本质是一样的,若想知道其原文是什么可以百度下这里不在叙述)
报数规则:
1、从第一个人开始报数为1,下一个人报数为上一个人报数加1
2、报数的最大值为2000,如果报数超过2000,则下一个人重新从1开始报数
l 要求实现函数
int OutFunc (unsigned int iTotalNum, unsigned int iKey)
【输入】iTotalNum:开始报数前的总人数, 0<iTotalNum<65535
iKey: 题目中要求的数目N
【输出】无
【返回】剩下的人的原来的位置
示例:
输入:iTotalNum =5, iKey =3
返回:4
输入:iTotalNum =15, iKey =3
返回:5
这问题来自华为2011校园编程赛
这个问题可以使用蛮力法解题,蛮力法这个名字听起来似乎有些愚蠢但这有时也不失是一种处理问题的方法(总比解决不了问题强)毕竟计算机的运算速度目前已将可达几百万次或者更多,有些问题也许对人来说蛮力就等于无解但对机器来说可能还是小case,蛮力法的总体思想就是不多想,试便所有可能老老实实一个个计算总会有一个是正确答案。
算法思想:
对于这个问题我们不妨让计算机去模拟这个问题的执行(因为对于我们来说可以很容易的让计算机模拟这个问题的执行)构造一个vector容器(或数组)容器下标来模拟第几个人例如下标为0就对应第一个人,容器的内容为人头顶的数字一开始都为零(为1时表示该人出圈),再定义一个account变量做报数用,当指针划过一个人account++,并且判断account%iKey是否=0,若等于零则该人头顶上的数字换为1,直到容器中只有一个人头顶0为止(当然为实现此项我们还需要一个outpersonc变量来进行对出圈人数的登记,当总人数-出圈人数=1时,我们就可知道容器中只有一个“幸运的”人)。
算法伪码:
while 总人数-出圈人数!=1
if 第i人没出圈
if 第i人报的数%iKey=0
该人出圈
出圈人数+1
继续报数
i=i+1
while true
return 遍历整个vector容器找出内容不为1的下标然后+1
算法代码c++
int OutFunc (unsigned int iTotalNum, unsigned int iKey)
{
if( iTotalNum>0&&iTotalNum<65535&&iKey<10&&iKey>1)//确认合适的人数范围和iKey范围
{
vector<int> circle(iTotalNum,0);
vector<int>::size_type point=0;//它指向哪个人哪个人报数
unsigned int account=1,outpersonc=0;
while(outpersonc<iTotalNum-1)
{
point=point%circle.size();//使“指针”形成一个环
if(circle[point]!=1)
{
if(account%iKey==0)
{
circle[point]=1;
outpersonc++;
}
account++;
}
point++;
if(account>2000)//若报数打过2000了则从1开始
{
account=1;
}
}
while(true)
{
point=point%circle.size();
if(circle[point]!=1)
{
return point+1;
}
point++;
}
}
else
{
return 0;
}
}
欢迎大家指出错误和问题所在。