每日一道算法题:约瑟夫环(c++)实现

问题描述:N个人坐成一个圆环(编号为1 - N),从第1个人开始报数,数到K的人出列,后面的人重新从1开始报数。问最后剩下的人的编号。
例如:N = 3,K = 2。2号先出列,然后是1号,最后剩下的是3号。

最直接的方法是暴力枚举法,第一一个标志数组label[n],初始化为0,当label[i]等于1时表示对应编号为i的人已经出列,直到最后一个人出列。
部分代码如下:(程序中将编号设定为0~n-1),便于理解。

#include<iostream>
#include<algorithm>
using namespace std;
int label[50]={0};
int main()
{    
  int N,k,final;
  cin>>N>>k;
  int m=N;
    int count=0;
    while(m)
    {  
       for(int i=0;i<N;i++)
       {
        if(!label[i])
        count++;
        if(count==k)
        {
          label[i]=1;
          count=0;
          m--;
          final=i;
      
        }
       }   
    }
    cout<<final+1;
 } 

暴力枚举法容易理解,但当N或K相差太大时,暴力枚举法就显得效率特别低。
现在换一种方式解决这个问题
假设现在有41人参与这个游戏,计数为3的出列
最开始时有这么多人

0 1 2 3 4 5 6 7 8 9···················39 40 

第一次出列,则是(3-1)%41=2出列,现在的情况是

0 1 3 4 5 6 7 8 9····························39 40

第一次出列后又重新从3%41=3开始计数,想当于上一步的0,那么可以将3当做头,既然是头那么就设置为0,则可以表示为

-3 -2 -1 0 1 2 3 4 5 6 ···························37

出现了负数,不便于计算,则给负数加上总人数(相当与接在最后一个人后面,实现了真正的环),表示为

38  39 40 0 1 2 3 4 5 6·····················37

这样就变成了一个40人的游戏,依次类推,第二次出列的是(3-1)%40=2号,对应的是第一步的(2+3)%41=5号
接下来出列的是(3-1)%39=2号,对应第二步的(2+3)%40=5号,对应第一步的(5+3)%41=8号
由此可得当人数为1时,胜利者为0号,那么根据以上推导公示推导为人数为n时胜利者的序号(实际序号只需要加1即可)

非递归代码如下

#include<iostream>
#include<algorithm>
using namespace std;
int main()
{  int N,k;
   cin>>N>>k;
	int last=0;
	for(int i=2;i<=N;i++)
	{
		last=(last+k)%i;
	}
	cout<<last+1;
 } 

参考文献:https://blog.csdn.net/okasy/article/details/79503398

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值