题目描述
约瑟夫环来源
首先,我们先来了解一下什么是约瑟夫环问题:
讲一个比较有意思的故事:约瑟夫是犹太军队的一个将军,在反抗罗马的起义中,他所率领的军队被击溃,只剩下残余的部队40余人,他们都是宁死不屈的人,所以不愿投降做叛徒。一群人表决说要死,所以用一种策略来先后kill所有人。
于是约瑟夫建议:每次由其他两人一起kill一个人,而被kill的人的先后顺序是由抽签决定的,约瑟夫有预谋地抽到了最后一签,在kill了除了他和剩余那个人之外的最后一人,他劝服了另外一个没死的人投降了罗马。
题目如下:
编号为1,2,…,n的n个人按顺时针方向围坐在一张圆桌周围,每人持有一个密码(正整数)。
开始任选一个正整数m作为报数上限值,从第一个人开始按顺时针方向自1开始报数,报到m时停止报数,报m的那
个人出列,将他的密码作为新的m值,从他顺时针方向的下一个人开始重新从1报数,数到m的那个人又出列;如
此下去,直至圆桌周围的人全部出列为止。要求按出列顺序输出n个人的编号。
输入:
第一行输入两个整数,依次表示人数n和初始化密码m,以空格间隔。
第二行依次输入n个整数,分别表示n个人的密码,以空格间隔。
7 20
3 1 7 2 4 8 4
输出:
按出列次序输出每个人的编号,以空格间隔。
6 1 4 7 2 3 5
方法一:数组
使用数组解决,对于数组的长度进行取余。
实现:线性存储看做环式
或者利用递推公式 每次删除的点的下标 i=i+m-1;
方法二:单向循环链表
建立单向循环链表时建议使用尾结点:
1.操作统一
2.时间复杂度。头找尾O(n),尾找头O(1)。
#include<stdio.h>
#include<stdlib.h>
typedef struct node{
int data;
int password;
struct node *next;
}ElemSN;
ElemSN * Create();
int n,m; //创建约瑟夫环
void Josephus(ElemSN * tail);
int main(void){
ElemSN *tail; //利用尾结点保证创建链表时操作的一致性(不用对第一个结点进行特殊判断)
tail=Create();
Josephus(tail);
}
ElemSN * Create(