约瑟夫问题(密码相同和密码不同两种情况)

1. 问题描述:
设有编号为1,2,…,n 的n(n>0)个人围成一个圈,每个人持有一个密码m。从第一个人开始报数,报到m 时停止报数,报m 的人出圈,再从他的下一个人起重新报数,报到m 时停止报数,报m 的出圈,……,如此下去,直到所有人全部出圈为止。当任意给定n 和m 后,设计算法求n 个人出圈的次序。
2. 数据结构设计:
因为约瑟夫环本身具有循环性,所以采用循环链表的存储结构。建立结构体如下:
typedef struct Node
{
DataType data;
struct Node *next;
};
为了统一对结点的操作,循环链表不带头结点,由头指针head指出。
3. 算法设计:
根据约瑟夫环问题的实际性,因包含的算法有:建立结点、创建循环链表、每个人密码相同时的约瑟夫函数、每个人密码不同时的约瑟夫函数。
(1) 建立结点:
采用循环链表的存储结构。如下:
typedef struct Node
{
DataType data;
struct Node *next;
}ListNode;
(2)创建循环链表:
由问题的实际性,创建一个为长度为n的循环链表,代表由n个人构成与瑟夫环。链表没有头结点,由头指针指出,该算法返回一个指向新建循环链表的头指针。
LinkList CreateDCList(int n)
{
LinkList head=NULL;
ListNode *s,*q;
int i;
for(i=1;i<=n;i++)//逐一为环中的人编号 
{
s=(ListNode*)malloc(sizeof(ListNode));//申请内存 
s->data=i;
s->next=NULL;
if(head==NULL)
{
head=s;
s->next=head;
}
else
{
s->next=q->next;
q->next=s;
}
q=s;
}
return head;//返回头指针 
}
(3)约瑟夫函数1(密码相同):
输入密码m,从头指针开始,每数一个数,指针指向下一个结点,数到m时,踢出指针所指的结点。进行下一次循环。直到所有的人都被踢出为止。
void Josephussame(LinkList head,int n,int m)
{
ListNode *p,*q;
int i,j;
p=head;
j=1;
while(p->next!=p)//当环中人数在两人以上时 
{
for(i=1;i<m;i++)//密码为m,故循环m次 
{
q=p;
p=p->next;
}
q->next=p->next;
printf("第%d个出环的是%d\n",j,p->data);
j++;
free(p);
p=q->next;
}
printf("第%d个出环的是%d\n",j,p->data);//最后一个人
}
(4)约瑟夫函数2(密码不同):
输入密码m,从头指针开始,每数一个数,指针指向下一个结点,数到m时,踢出指针所指的结点。进行下一次循环。直到所有的人都被踢出为止。
void Josephusdifferent(LinkList head,int n,int *a)
{
ListNode *p,*q;
int i,m,j;
p=head;
m=a[1];
j=1;
while(p->next!=p)
{
   
for(i=1;i<m;i++)
{
q=p;
p=p->next;
}
q->next=p->next;
printf("第%d个出环的是%d\n",j,p->data);
j++;
m=a[p->data];
free(p);
p=q->next;

}
printf("第%d个出环的是%d\n",j,p->data);
}
4. 附录(源代码)
#include <stdlib.h>
#include <cstdio>
#include <malloc.h>
typedef int DataType;//循环链表存储结构 
typedef struct Node
{
DataType data;
struct Node *next;
}ListNode,*LinkList;
//创建一个新的循环链表 
LinkList CreateDCList(int n)
{
LinkList head=NULL;
ListNode *s,*q;
int i;
for(i=1;i<=n;i++)//逐一为环中的人编号 
{
s=(ListNode*)malloc(sizeof(ListNode));//申请内存 
s->data=i;
s->next=NULL;
if(head==NULL)
{
head=s;
s->next=head;
}
else
{
s->next=q->next;
q->next=s;
}
q=s;
}
return head;//返回头指针 
}
//密码相同时的约瑟夫函数 
void Josephussame(LinkList head,int n,int m)
{
ListNode *p,*q;
int i,j;
p=head;
j=1;
while(p->next!=p)//当环中人数在两人以上时 
{
for(i=1;i<m;i++)//密码为m,故循环m次 
{
q=p;
p=p->next;
}
q->next=p->next;
printf("第%d个出环的是%d\n",j,p->data);
j++;
free(p);
p=q->next;
}
printf("第%d个出环的是%d\n",j,p->data);//最后一个人 
}
//密码不同时的约瑟夫函数 
void Josephusdifferent(LinkList head,int n,int *a)
{
ListNode *p,*q;
int i,m,j;
p=head;
m=a[1];
j=1;
while(p->next!=p)
{
   
for(i=1;i<m;i++)
{
q=p;
p=p->next;
}
q->next=p->next;
printf("第%d个出环的是%d\n",j,p->data);
j++;
m=a[p->data];
free(p);
p=q->next;

}
printf("第%d个出环的是%d\n",j,p->data);
}
int main()
{
LinkList h;
int n;
printf("请输入环中的人数:\n");
scanf("%d",&n);
printf("请选择密码形式:\n单一密码请输入1\n各人不同请输入2\n");
int chose;
chongxin:
scanf("%d",&chose);//选择密码形式 
if(chose==1)
{
int m;
printf("请输入密码\n");
scanf("%d",&m);
h=CreateDCList(n);
Josephussame(h,n,m);
}
else if(chose==2)
{
int a[n+1];
printf("请输入各人密码\n");
for(int i=1;i<=n;i++)
  scanf("%d",&a[i]);
  h=CreateDCList(n);
  Josephusdifferent(h,n,a);
}
else 
{
printf("输入错误,请重新输入:\n");
goto chongxin;//输入错误时,返回到选择密码形式状态 
}
return 0;
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Guanngxu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值