传说约瑟夫当年活下来就是靠快速计算这个问题。
n 个人围成一圈,编号依次为 1,2,3…n。从第一个人开始报数,数到 m 的人出列,再由下一个人重新从 1 开始报数,数到 m 的人再出圈。以此类推,直到所有的人都出列。请输出依次出圈人的编号。
输入格式
两个整数 n,m, 1<=n,m<=100
输出格式
n 个用空格分隔的整数,表示出圈人的编号。
#include<stdio.h>
int main()
{// 约瑟夫环的简单问题
int n,m,d=0,k=0,i,a[100]={0};//随便定义了一个100个内存的数组值为0
scanf("%d%d",&n,&m);//n为人数,m为报号数,k为实际计数,i为原座位顺序数
for(i=1;k!=n;i++)//d为暂时计数(0到m间循环)
{
if(i>n)//这个步骤可以实现数组像圆圈一样多次重复的循环
{
i=1;//i代表每个人原先的顺序位置
}
if(a[i]==0)//数组的定义0和1可以实现标记未出局和出局的具体人
{
d++;//如果进入循环,暂时计数便+1;
if(d==m)//当暂时计数达到出局的位置,令数组值为1,出局
{
d=0;//使暂时计数程序循环
a[i]=1;
printf("%d",i);//输出出局的具体座位数
if(k!=n)//此处为格式需求,只要不是最后一行,其间输出空格
{
printf(" ");
}
k++;//此处的K递增为出局的人数,该for循环语句的终止条件为出局数=n
}
}
}
}
题目二:
约瑟夫
要点.模拟法,做好问题向符号的映射,然后按照题目描述的过程,在符号上进行操作。
描述
设 n(n>0)个人围成一个环,n 个人的编号分别为1,2,…,n,从第 1 个人开始报数,报到 m 时停止报数,报 m 的人出环,再从他的下一个人起重新报数,报到 m 时停止报数,报m的人出环,……,如此下去,直到所有人全部出环为止。对于任意给定 n 和 m,求 n 个人出环的次序。
输入
空格分隔的两个小于10000的非负整数,第一个表示人数,第二个表示需要报的数目。
输出
最后一个出环人的编号
示例
输入
5 3
输出
4
#include <iostream>
using namespace std;
int main()
{
int arr[99999],k=0,c=0,n,m;
cin>>n>>m;//输入n个人和报数到m出局;
for(int i=1;i<=n;i++)
{
arr[i]=1;
}//用arr数组标记每个人,如果arr[i]为1,表示未出局,若某个人数到m,令他出局,则将他标记为0,出局。
for(int i=1;;i++)
{
//cout<<i<<endl;
if(arr[i]==1)//如果未出局,则继续数数
{
k++;//报数+1
if(k==m)//如果k数数报到m,令这个人出局,标记为0,c表示出局的人数
{
arr[i]=0;
c++;
k=0;//报数到m后重新归0,重新从0开始数
}
}
if(c==n)//如果c出局人数到n,则可以停止了,所有人都出局了,游戏结束
{
cout<<i<<endl;//当前i为最后一个出局人的位置
break;
}
if(i==n) i=0;//每个人座位顺序遍历完后从0开始
}
}
#include <iostream>
using namespace std;
int main()
{
int r[10000]={0}, n, m;
int counter, i = -1, num = 0;
cin>>n>>m;
while(num<n-1){//num是出局人数
counter=0;
while(counter<m){
i=(i+1)%n;//counter实现报数遍历循环,i是每个人的座位号
if(r[i]!=1) counter++;
}
r[i]=1; num++;
}
for (i = 0; i < n; i++)
if (r[i] == 0) //返回编号
cout << i+1;
return 0;
}
这个代码建议读者多敲几遍,边理解边敲。
请关注我,真诚地感谢读者的支持,