约瑟夫问题
约瑟夫问题是个著名的问题:N个人围成一圈,第一个人从1开始报数,报M的将被杀掉,下一个人接着从1开始报。如此反复,最后剩下一个,求最后的胜利者。
例如只有三个人,把他们叫做A、B、C,他们围成一圈,从A开始报数,假设报2的人被杀掉。
首先A开始报数,他报1。侥幸逃过一劫。
然后轮到B报数,他报2。非常惨,他被杀了
C接着从1开始报数
接着轮到A报数,他报2。也被杀死了。
最终胜利者是C
普通解法
#include <bits/stdc++.h>
using namespace std;
int a[100]={0};//0表示没有出局,1表示已出局
int main() {
int n,m;//n个人,报到m号的人出局
int cnt=0,k=0;//cnt表示目前出局的人数,k记录当前报到了多少号
int i=0;//i相当于一个指针,遍历整个数组,然后又从头开始遍历有人出局后的数组;
cin>>n>>m;
while(cnt!=n){
i++;
if(i>n) i=1;
if(a[i]==0){//当他未出局时
k++;
if(k==m){//当报到了m号时
a[i]=1;//让这个人出局,并将他标记为1
cnt++;//出局人数加一
cout<<i<<" ";//注:当人员是从0开始编号时,应该输出 i-1(!!!!!!)
k=0;//清空k,从1开始报数
}
}
}
return 0;
}
/*
人员从1开始编号:1 2 3 4 5 6 7 8 9 10
10 3
3 6 9 2 7 1 8 5 10 4
*/
/*
人员从0开始编号: 0 1 2 3 4 5 6 7 8 9
10 3
2 5 8 1 6 0 7 4 9 3
*/
公式法
f (N,M) = ( f (N−1,M) + M ) %N
f(N,M)表示,N个人报数,每报到M时杀掉那个人,最终胜利者的编号
f ( N − 1 , M ) f(N-1,M)f(N−1,M)表示,N-1个人报数,每报到M时杀掉那个人,最终胜利者的编号
//这里的公式法:人员从0开始编号
#include<bits/stdc++.h>
using namespace std;
int n,m;
int main(){
cin>>n>>m;
int success=0;
for(int i=2;i<=n;i++){
success=(success+m)%i;
}
cout<<success;//这里输出的是当人员从0开始编号时的成功的那个人,
//如果人员从1开始编号,那么最后成功的那个人是:success+1.
return 0;
}