模拟报数游戏(约瑟夫环问题)
问题描述:有n个人围成一圈,从1开始按顺序编号,从第一个人开始从1到k报数,报到k的人退出圈子;然后圈子缩小,从下一个人继续游戏,如此下去,直到留下最后一个人。要求定义函数实现。
输入:int类型的初始n与自由指定报数k。
输出:每个人的退出顺序编号。
优化目标:无。
算法描述:
#include <stdio.h>
#define MAXN 20
void CountOff( int n, int m, int out[] );
int main()
{
int out[MAXN], n, m;
int i;
scanf("%d %d", &n, &m);
CountOff( n, m, out );
for ( i = 0; i < n; i++ )
printf("%d ", out[i]);
printf("\n");
return 0;
}
/* 你的代码将被嵌在这里 */
void CountOff( int n, int m, int out[] )
{
int i,j,count=-1,flag;
for(i=0;i<n;i++)
out[i]=0;
for(i=1;i<=n;i++)
{
j=0;
while(j!=m)
{
count++;
if(out[count%n]==0)
j++;
}
out[count%n]=i;
}
}
输入:
11 3
输出:
4 10 1 7 5 2 11 9 3 6 8
升级版:
双向循环链表解决约瑟夫环问题
问题描述:
编号为1,2,…,n的n个人按顺时针方向围坐在一张圆桌周围,每人持有一个密码(正整数)。一
开始任选一个正整数m作为报数上限值,从第一个人开始按顺时针方向自1开始报数,报到m时停止报数,报m的那个人出列,将他的密码作为新的m值,从他顺时针方向的下一个人开始重新从1报数,数到m的那个人又出列;如此下去,直至圆桌周围的人全部出列为止。要求按出列顺序输出n个人的编号。
输入:第一行输入两个整数,依次表示人数n和初始化密码m,以空格间隔。
第二行依次输入n个整数,分别表示n个人的密码,以空格间隔。
输出:按出列次序输出每个人的编号,以空格间隔。
#include<stdio.h>
#include<stdlib.h>
typedef struct node{
int data; //手持密码值
int num; //编号
struct node *prev;
struct node *next;
}Jose_node;
//debug打印链表
void print_list(Jose_node *head,int n){
Jose_node *p = head;
while(n--){
printf("data = %d,num = %d \n",p->data,p->num);
p = p->next;
getchar();
}
}
//创建链表
Jose_node *Creatlist(){
Jose_node *head = (Jose_node*)malloc(sizeof(Jose_node));
head->data = 0;
head->next = head;
head->prev = head;
return head;
}
//链表输入
int Insertlist(Jose_node *head){
int sum,pwd;
Jose_node *p = head;
scanf("%d %d",&sum,&pwd);
int n = sum;
//在头后开始插入结点,所以结点 编号 为 2
int num = 2;
//头的编号为1
head->num = 1;
//插入结点
while(sum--){
Jose_node *q = (Jose_node*)malloc(sizeof(Jose_node));
scanf("%d",&p->data);
q->num = num;
num++;
q->next = head;
head->prev = q;
p->next = q;
q->prev = p;
p = p->next;
}
//释放空结点
p = head->prev;
p->prev->next = p->next;
p->next->prev = p->prev;
free(p);
//打印链表
/* print_list(head,n); */
//返回密码值
return pwd;
}
//约瑟夫环
void Josephus(Jose_node *head,int pwd){
int n = 1;
Jose_node *p = NULL;
while(head){
//与密码相同
if(n == pwd){
printf("%d ",head->num);
//结束
if(head->next == head){
printf("\n");
free(head);
break;
}
//重置密码
pwd = head->data;
//释放结点
p = head;
head = head->next;
p->prev->next = p->next;
p->next->prev = p->prev;
free(p);
//从 1 开始
n = 1;
}else{
//继续游戏
head = head->next;
n++;
}
}
}
int main()
{
//创建链表
Jose_node *head = Creatlist();
//添加数据
int pwd = Insertlist(head);
//约瑟夫环
Josephus(head,pwd);
return 0;
}
输入:
7 20
3 1 7 2 4 8 4
输出:
6 1 4 7 2 3 5
算法流程图:
总结:其实约瑟夫环问题可以使用多种方法解决(还有静态链表等),不使用链表可能你们觉得要简单很多,但是当游戏变得越复杂时,利用循环链表就会让你大开眼界。