什么时约瑟夫环问题?
约瑟夫问题,是一个计算机科学和数学中的问题,在计算机编程的算法中,类似问题又称为约瑟夫环,又称“丢手绢问题”。
问题的大致内容就是:一共有N个人,从1开始报数,报到p的人出局,之后下一个人再从1开始报数,同样报到p的人出局,直到只剩最后一个人为止,那剩下的这一个人就是胜利者。
示例图:
此图中,外围数字为对应人的出出局顺序
当然原问题是比较简单的,那如果按退出顺序输出每个退出人的原序号该怎么实现呢?
问题分析:
1、如何判断出局
这里我们可以定义一个数组(长度视情况而定)可以将数组初始化为0,定义k来表示数组成员的报数,每次循环时k++,然后判断k是否等于p,若等于p则让arr[i] = 1;那么下次循环时判断arr[i]的值,若为1则跳过该元素。
2、如何循环
在此问题中,不是简单的对数组进行遍历,所以再想用for(i = 0;i <n;i++)显然是行不通的,
那我们该如何进行循环呢?
这里我们定义count来记录已经淘汰的人数,当淘汰人数count = n时则结束循环。
那么新的问题又出现了,当进行到最后一个人时如何返回从第一个人开始呢?
3、如何返回重新开始
其实这个问题不难解决,我们可以定义一个temp = n,在循环的最后判断i的值,如果i==temp,
这令i=0;就可以重新开始了。
OK主要问题就分析完了,话不多说,直接上代码。
代码:
#include <stdio.h>
#define N 3000
void joseph(int *arr,int n,int p);
int main()
{
int arr[N] = {0};
int n,p;
printf("请输入参加人数n和淘汰条件:");
scanf("%d %d",&n,&p);
printf("淘汰循序: ");
joseph(arr,n,p);
return 0;
}
void joseph(int *arr,int n,int p)
{
int count,k,i,b;
count = 0; //记录出局的人数
k = 0; //每个成员报的数
i = 0;
int temp;
temp = n;
/*
这里定义temp的值为总人数是为了当数组遍历到最后一个后再回到第一个
即:当 i == temp时 令 i = 0;
*/
while(count < n)
{
if(arr[i] == 0)
{
k++;
if(k == p)
{
arr[i] = 1;
b = i+1;
printf("%d ",i+1);
count++;
k = 0;
}
}
i++;
if(i == temp)
{
i = 0;
}
}
}