写了n个小时才改完,有点小激动。。。。
约瑟夫问题 又称丢手绢问题
n个人(编号0~(n-1)),从0开始报数,报到(m-1)的退出,剩下的人继续从0开始报数。求胜利者的编号。
第一种是递推方式
如何知道(n-1)个人报数的问题的解?对,只要知道(n-2)个人的解就行了。(n-2)个人的解呢?当然是先求(n-3)的情况 ---- 这显然就是一个倒推问题!
递推公式
f[1]=0;
f[i]=(f[i-1]+m) mod i; (i>1)
//来自百度百科
#include <iostream>
using namespace std;
int main(){
int n,m;
cin>>n; //人数
cin>>m; //数到m退出
int a[n+1];
a[0]=0;
for(int i=1;i<20;i++){
a[i]=(a[i-1]+m)%i;
}
cout<<a[n];
return 0;
}
第二种是将过程模拟出来
#include<iostream>
using namespace std;
int yuesefu(int n,int m);
int next(int *a,int n,int m,int pos);
int main(){//约瑟夫问题数组模拟
int n,m; //n为人数,m为数到m时退出
//将数组中元素不设为0,当退出时,数组中元素为0,写循环 判断是否为0,当不为0时++
cin>>n;
cin>>m;
cout<<yuesefu(n,m);
return 0;
}
int yuesefu(int n,int m){
int pos; //设置一个断点 ,初始为0
int a[n+1];
pos=m;
for(int i=1;i<=n;i++){ //将每个数组中元素赋值,最后只要输出数组中值即为元素位置
a[i]=i;
}
a[pos]=0; //第一个断点为 m,将他的值归为0
cout<<pos<<endl;
for(int i=0;i<n-1;i++){ //n个元素n-1次后剩一个
pos=next(a,n,m,pos); //开始寻找断点
cout<<pos<<endl; //输出每个断点位置
a[pos]=0;
}
pos=next(a,n,m,pos);
return a[pos];
}
int next(int *a,int n,int m,int pos){
int count=0;
int b=pos+1; //现在的数组位置
for(int i=0;;i++){
if(b<=n){
if(a[b]!=0){ //如果元素不为0
count++; //计数器++
if(count==m){ //当计数器等于m时
return b;
break;
}
b++;
}else if(a[b]==0){ //若元素为0
b++;
continue;
}
}else{ //如果b>n,取模
b=1;
if(a[b]){
count++;
if(count==m){
return b;
break;
}
b++;
}else{
b++;
continue;
}
}
}
}
还可以用链表来写,但是现在还没有学到,等学到补上。