前言
简单问题,写的不好,大佬见谅.
如有疏漏,恳请指正,小编垂首.
问题描述:
约瑟夫环问题:
有七个小朋友,分别编号是1,2,3…,7,按照从小到大顺时针围成一个圆圈,第一个小朋友从1开始报数,然后按照顺时针方向报数,每次报数增加一,每个报5的人会离开队伍,然后下一个小朋友从1开始报数,直到剩最小一个小朋友为止。
问题解析:
本题是一个f(m,n)问题,其中m为人数,n为间隔数
1 2 3 4 5 6 7
6 7 1 2 3 4
4 6 7 1 2 4 6 7 1 2
4 6 7 1 4 6 7 1
6 7 1 6 7 1
1 6 1 6 1 6
6
出局顺序为5 3 2 4 7 1
顺序思维很难找到规律,我们只能注意到新一轮的开始是由上一轮出局的人决定的
但由于每一轮都有人出局,所以无法用下标来记录,用计数来运算的话,可以使用循环链表实现
但我比较懒,不想写链表
所以列举一下找找y= f(m,n)的规律n = 5
m=1,y=0 (一个人怎么玩😒😭)
递归就好啦
实现代码:
代码如下(示例):
#include<iostream>
using namespace std;
int ysf(int n,int k) {
if (n == 2) return k % 2;//若只有两人,则k为偶数,下标0存活,否则下标1存活
return (k+ysf(n - 1, k)) % n;//从本轮死亡的人k开始数在n-1轮中存活的人的下标,对n取余,防止溢出
}
int main() {
int n, k;
cin >> n >> k;
//约瑟夫环问题//返回的下标+1
cout<<ysf(n, k)+1;
return 0;
}
代码如下:
as everyone knows 递归可以写成循环(能不递归就不递归)
#include<iostream>
using namespace std;
int ysf(int n,int k) {
int ans = 0;
for (int i = 2; i <= n; i++) {
ans = (k + ans) % i;
}
return ans;
}
int main() {
int n, k;
cin >> n >> k;
//约瑟夫环问题//返回的下标+1
cout<<ysf(n, k)+1;
return 0;
}
注意事项
折腾了1个多小时,勉强用自己的思维理解了,但倒不出多少.
不会的小伙伴可以去看大佬的题解,
测试案例:
总结
正着不行,逆着来,只要有规律,总能找到