由猴子选王(约瑟夫环)展开来(数组与链表)

题目示例
一堆猴子有m个,编号分别是1,2,3 …m,这m个猴子按照编号1,2,…,m的顺序围坐一圈,然后从第1开始数,每数到第n个,该猴子就要离开此圈,这样依次下来,直到圈中只剩下最后一只猴子,则该猴子就为大王。
要求:m和n从键盘输入,分别采用向量及链表两种存储方式实现该问题的求解。

数组解决方案
·在一个数组中,数组中用1表示猴子在圈中,用0表示猴子已经出圈,数组下标对应与猴子编号对应(例如数组元素p[0]值为1,表示第1只猴子尚在圈中,即p[i]代表编号为i+1的猴子是否在圈中)。
·一只猴子出圈,则将对应的数组值置为0;在报数过程中,要略过值为0的猴子。

#include <stdio.h>
#include <stdlib.h>
#define maxsize 100
void king(int m,int n)
{
    int p[maxsize],q[maxsize];
    int i,j,t;
    t=-1;//t为报数的位置,第一只猴子在位置0(每步需要先加一)
    for(i=0;i<m;i++)
    {
       p[i]=1;//数组初始化,未出圈猴子位置记为1
    }
    printf("猴子出圈顺序依次为:\n");
    for(i=1;i<=m;i++)
    {
        j=1;//报数用
        while(j<=n)
        {
            t=(t+1)%m;//当报数为报至需要出圈时,报数位置加一
                     // 因为报数位可能会超过m,故取余回到开头
            if(p[t]==1)j++;//当所在位置非空时,报数加一
        }
        p[t]=0;//已经报数了n个,t处猴子出圈
        printf("%d\n",t+1);//因为数组从零记,实际位置需要加一
        q[i]=t+1;//将每次出圈的猴子标号记录下来,用于最后得出王者
    }
    printf("王者为%d",q[m]);
}
int main()
{
   int m,n;
   printf("请输入猴子个数(100以内)m和每出圈一个需要报的个数n\n");
   scanf("%d,%d",&m,&n);
   king(m,n);
   return 0;
}

链表解决方案
·构建一个循环链表,出圈猴子对应结点删除,当链表中只有一个结点时结束,猴王选出

#include <stdio.h>
#include <stdlib.h>
typedef struct node    //定义链表节点类型
{
    int data;
    struct node*next;
}linklist;
void creat(int n,int m)
{
    linklist *head,*p,*s,*q;
    int i,total;
/*创建循环链表,头节点也存储信息*/
     head=(linklist*)malloc(sizeof(linklist));
     p=head;
     p->data=1;
     p->next=p;
/*初始化循环链表*/
 for(i=2;i<=m;i++)
 {
     s=(linklist*)malloc(sizeof(linklist));
     s->data=i;
     s->next=p->next;
     p->next=s;
     p=p->next;
 }
  p=head;
  /*保存节点总数*/
  total=m;
  q=head;

  while(total!=1)  //只剩一个节点时停止循环
  {
      /* 报数过程,p指向要删除的结点*/
      for(i=1;i<n;i++)
      {
          p=p->next;
      }
      printf("%d\n",p->data);//输出要出圈的猴子序号
    
    /*q指向p结点的前驱 */
    while(q->next!=p)
    {
        q=q->next;
    }
    
    /* 删除p结点*/
    q->next=p->next;
    /* 保存被删除的结点指针*/
    s=p;
    /* p指向被删除结点的后继*/
    p=p->next;
    /* 释放被删除的结点*/
    free(s);
    /* 结点个数减一*/
    total--;
  }
  int king;
  king=p->data;
  free(p);
  printf("king is %d\n",king);
  return 0;

}

知识铺垫延伸:

约瑟夫环问题
N个人围成一圈,从第一个开始报数,第M个将被杀掉,最后剩下一个,其余人都将被杀掉。

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值