约瑟夫环
约瑟夫环(约瑟夫问题)是一个数学的应用问题:已知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;
}