数组和链表处理约瑟夫环问题

已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。

#include <stdio.h>
#include <stdlib.h>
 
int main() 

 
   int k=0,n=0,s=0,m=0;           //k为1,2,3报数时的计数变量,m为退出人数
   int num [100];
   int *p=num;
   int i;
   printf("Enter the number of person and the key:");
   scanf("%d%d",&n,&s);
   for (i=0; i<n; ++i)
   { 
      *(p+i)=i+1;                //以1至n为序给每个人编号
   }                          
   i = 0;
   while (m<(n-1))              //当未退出人数大于1时执行循环体   (n-m) > 1
   {
      if (*(p+i)!=0)
          k++;
      if (k==s)                //对退出的人编号置为0
      {
          printf("%d/n",*(p+i));                     
          *(p+i)=0;
          k = 0;
          m++;
      }
       i++;
      if (n==i)               
           i = 0;               //报数到尾后,i恢复为0
    }
     while (*p==0)
        p++;
    printf("The last one is :%d/n",*p);
    system("PAUSE");     
    return 0;
}

链表:
======================================================
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
 
/* 结构体和函数声明 */
typedef struct _node_t
{
    int             n_num;
    struct _node_t *next;
} node_t;
 
node_t         *node_t_create(int n);
node_t         *node_t_get(node_t **pn, int m);
 
node_t * node_t_create(int n)
{
    node_t *p_ret   = NULL;
 
    if (0 != n)
    {
        int     n_idx   = 1;
        node_t *p_node  = NULL;
 
        /* 构造 n 个 node_t */
        p_node = (node_t *) malloc(n * sizeof(node_t));
        if (NULL == p_node)
            return NULL;
        else
            memset(p_node, 0, n * sizeof(node_t));
 
        /* 内存空间 申请 成功 */
        p_ret = p_node;
 
 
        for (; n_idx < n; n_idx++)
        {
            p_node->n_num = n_idx;
            p_node->next = p_node + 1;
            p_node = p_node->next;
        }
        p_node->n_num = n;
        p_node->next = p_ret;
    }
 
    return p_ret;
}
 
 
int main()
{
    int     n, m;
    node_t *p_list, *p_iter;
    printf("Please enter the total and the key :");
    scanf("%d%d",&n,&m);
    printf("The total num is : %d /nThe   key   is   : %d /n",n,m);
 
    /* 构造环形单向链表 */
    p_list = node_t_create(n);
 
    /* Josephus 循环取数 */
    p_iter = p_list;
    m %= n;
    while (p_iter != p_iter->next)
    {
        int i   = 1;
 
        /* 取到第 m-1 个节点 */
        for (; i < m - 1; i++)
        {
            p_iter = p_iter->next;
        }
 
        /* 输出第 m 个节点的值 */
        printf("%d ", p_iter->next->n_num);
 
        /* 从链表中删除第 m 个节点 */
        p_iter->next = p_iter->next->next;
        p_iter = p_iter->next;
    }
    printf("%d ", p_iter->n_num);
 
    /* 释放 申请 的空间 */
    free(p_list);
 
    system("PAUSE");

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我可以为您讲解一下利用数组模拟双向链表来解决约瑟夫环问题的方法。 首先,我们需要了解约瑟夫环问题的基本情况。这个问题的描述是:有n个人围成一圈,从第一个人开始报数,报到m的人出圈,然后从出圈的下一个人开始重新报数,直到所有人都出圈为止。我们需要编写程序来模拟这个过程,并输出出圈的顺序。 为了解决这个问题,我们可以使用一个数组来模拟双向链表数组的每一个元素表示一个人,包含三个属性:前驱节点、后继节点和是否出圈。初始时,我们可以将数组中每个元素的前驱节点和后继节点设置成相邻的元素,形成一个环状结构。然后,我们可以依次遍历这个数组,找到下一个未出圈的人,并将当前人的后继节点指向下一个未出圈的人。当我们找到第m个未出圈的人时,我们可以将其标记为已出圈,并将其前驱节点的后继节点指向其后继节点,从而将其从链表中删除。最后,我们需要输出出圈的顺序,即每个人的编号。 下面是利用数组模拟双向链表解决约瑟夫环问题的示例代码: ```c++ #include <iostream> using namespace std; const int MAXN = 100; // 约瑟夫环的人数上限 int n, m, cnt; // n表示约瑟夫环的人数,m表示报数的次数,cnt表示当前未出圈的人数 int pre[MAXN], nxt[MAXN], out[MAXN]; // pre表示每个人的前驱节点,nxt表示每个人的后继节点,out表示每个人是否出圈 int main() { // 读入约瑟夫环的人数和报数的次数 cin >> n >> m; // 初始化数组,构建双向链表 for (int i = 1; i <= n; i++) { pre[i] = i - 1; nxt[i] = i + 1; out[i] = 0; } pre[1] = n; nxt[n] = 1; // 开始模拟约瑟夫环的过程 cnt = n; int cur = 1; // 从第一个人开始报数 while (cnt > 0) { for (int i = 1; i < m; i++) { cur = nxt[cur]; // 找到下一个未出圈的人 } out[cur] = 1; // 标记当前人已出圈 nxt[pre[cur]] = nxt[cur]; // 将当前人从链表中删除 pre[nxt[cur]] = pre[cur]; cnt--; // 未出圈的人数减1 cur = nxt[cur]; // 从下一个人开始重新报数 } // 输出出圈的顺序 for (int i = 1; i <= n; i++) { if (out[i]) { cout << i << " "; } } cout << endl; return 0; } ``` 希望这个解法能够帮助到您解决约瑟夫环问题

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值