约瑟夫环

约瑟夫环

约瑟夫环(约瑟夫问题)是一个数学的应用问题:已知n个人(以编号1,2,3…n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。通常解决这类问题时我们把编号从0~n-1,最后[1] 结果+1即为原问题的解。

一般的解决方法

直观上,通过循环链表非常的简单,只需要循环删除指定节点就可以了,但建循环链表的过程非常的繁琐,有没有更简单的方法。

动态规划的解决法案

动态规划从以下四个方面考虑问题:

  • 状态(State)
  • 状态间的转移方程(Function)
  • 状态的初始化(Initialization)
  • 返回结果(Answer)

状态定义

f(i)表示第i个人报数为m出列人的编号
f(i+1) 表示第i+1个人报数为m出列人的编号

状态间的转移方程

由约瑟夫问题可得到的递推方程为:f(i+1) = f(i) + m
假设有n个人,则编号范围为0~n-1的环,因此退出的人的编号只能在0~n-1之间,那么 f(i+1) = (f(i) + m) % n

状态的初始化

当约瑟夫问题只有一个人时,则f(1) = 0,即表示第 1 个报数为m的编号为0

返回结果

表示第n个报数为m的人的编号:f(n)

代码

#include<iostream>  
using namespace std;  
int main()  
{  
    int N;//人的总个数  
    int M;//间隔多少个人  

    cin>>N;  
    cin>>M;  
    int result=0;//N=1情况  
    for (int i=2; i<=N; i++)  
    {  
        result=(result+M)%i;  
    }  
    cout<<"最后退出的人是:"<<result + 1<<endl;  // 编号从1开始
    return 0;  
}  

参考

约瑟夫环问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值