约瑟夫问题/报数问题的几种解法
题目
(洛谷)约瑟夫问题:n个人(n<=100)围成一圈,从第一个人开始报数,数到m的人出列,再由下一个人重新从1开始报数,数到m的人再出圈,……依次类推,直到所有的人都出圈,请输出依次出圈人的编号。
(PTA)报数:有n个人围成一圈,按顺序从1到n编好号。从第一个人开始报数,报到m(<n)的人退出圈子;下一个人从1开始报数,报到m的人退出圈子。如此下去,直到留下最后一个人。
本题要求编写函数,给出每个人的退出顺序编号。
输入样例
10 3
输出样例
3 6 9 2 7 1 8 5 10 4
解法一一般
由于这两个平台里这个题目给的数据很小,所以可以直接c或者c++
#include<iostream>
using namespace std;
int n,m,i,j,k,p[105];//主函数外定义,默认为0;
//p数组记录在(0)或不在(1),
int main(void)
{
cin>>n>>m;
i=n;
while(i){//全部退出则循环结束;
j++;
if(j>n) j-=n;
if(p[j]==0) k++;
if(k==m){
cout<<j<<" ";
p[j]=1;
k=0;
i--;
}
}
return 0;
}
解法二队列
运用C++的队列进行模拟,简单愉悦;
#include<iostream>
#include<queue>//队列头文件
using namespace std;
int main()
{
int n,m,k=1;
queue<int>q;
cin>>n>>m;
for (int i=1;i<=n;i++) q.push(i);//排入队列
//q.push将元素压入队尾
while(!q.empty())//在队列不为空时继续模拟
//q.empty队列为空时true,反之false
{
if (k==m)
{
cout<<q.front()<<" ";//输出
q.pop();//删除队首元素但不返回
k=1;
}
else
{
k++;
q.push(q.front());//排至队尾
//q.front返回队首元素但不删除
q.pop();
}
}
return 0;
}
解法三vector
还是C++,运用vector动态数组,erase使得我们可以丢一个删一个
#include<bits/stdc++.h>
using namespace std;
int main(void){
int n,m;
cin>>n>>m;
vector<int>no;
for(int i=1;i<=n;i++)
no.push_back(i);//在尾部插入一个元素;
int num=0;
while(no.size()!=0)
{
num=(num+m-1)%no.size();
//上面公式简单的解释,动态数组删去一个元素后,之后的下标都会减一
cout<<no[num]<<" ";
no.erase(no.begin()+num);
}
return 0;
}