【算法竞赛】实现约瑟夫问题的四种方法(附手绘图详解)

简介: 【算法竞赛】实现约瑟夫问题的四种方法(附手绘图详解)

题目描述


n 个人围成一圈,从第一个人开始报数,数到 m 的人出列,再由下一个人重新从 1开始报数,数到 m 的人再出圈,依次类推,直到所有的人都出圈,请输出依次出圈人的编号。


输入格式

输入两个整数 n,m。


输出格式

输出一行 n 个整数,按顺序输出每个出圈人的编号。


输入输出样例

输入


10 3



输出


3 6 9 2 7 1 8 5 10 4



说明/提示

1≤m,n≤100


1.动态单向链表实现的方法


动态链表需要临时分配链表节点,使用完毕后需要释放链表节点,动态链表的优点是能及时释放空间,不用使用多余的内存,缺点是需要管理空间,比较容易出错。


#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
struct node
{
  int data;
  node* next;//单向链表,一个next指针
};
int main()
{
  int m, n;
  scanf("%d%d", &n, &m);
  node* head, * p, * now, * prev;
  head = new node; head->data = 1; head->next = NULL;//分配第一个节点,数据置为1
  now = head;
  for (int i = 2; i <= n; i++)
  {
  p = new node; p->data = i; p->next = NULL;//把申请的新节点链接到前面的链表上
  now->next = p;
  now = p;
  }
  now->next = head;
  //上面是建立链表。
  now = head, prev = head;
  while ((n--) > 1)
  {
  for (int i = 1; i < m; i++)//数到m为止
  {
    prev = now;//类似于单链表的元素删除,记录前一个位置,用于下面跳过第m个节点
    now = now->next;
  }
  printf(" %d ", now->data);
  prev->next = now->next;
  delete now;
  now = prev->next;
  }
  printf(" %d", now->data);//最后一个节点的打印
  delete now;//释放掉最后一个节点
  return 0;
}


为了方便大家理解思路,我做出了第一次while循环的图示 ,为了简便,节点就设置成了4个,m的值就设置为3。


5fb154712653a62023619766c195ee4f_c4852cde46e04deea1acf240afae2583.jpeg


2.用结构体数组实现单向静态链表实现的方法


静态链表较动态链表省去了动态分配和释放储存空间的麻烦。可以加快编码的速度。


#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
const int N = 100;//定义静态链表的空间大小
struct node
{
  int id, nextid;
}nodes[N];
int main()
{
  int n, m;
  scanf("%d%d", &n, &m);
  nodes[0].nextid = 1;
  for (int i = 1; i <= n; i++)
  {
  nodes[i].id = i, nodes[i].nextid = i + 1;
  }
  nodes[n].nextid = 1;
  int now = 1, prev = 1;
  while ((n--) > 1)
  {
  for (int i = 1; i < m; i++)
  {
    prev = now;
    now = nodes[now].nextid;
  }
  printf(" %d ", nodes[now].id);
  now = nodes[prev].nextid;
  }
  printf(" %d", nodes[now].nextid);
  return 0;
}


同样是画了个简图方便理解(不要嫌弃我字丑🤗🤗🤗)


f1885a9e5a9a65547195c8797e7a6391_9091ac939f664275971d751b2827a167.jpeg


3.用结构体数组实现双向静态链表实现的方法


#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
const int N = 100;
struct node
{
  int id;
  int preid, nextid;//前后节点
}nodes[N];
int main()
{
  int n, m;
  scanf("%d%d", &n, &m);
  nodes[0].nextid = 1;
  for (int i = 1; i <= n; i++)
  {
  nodes[i].id = i;
  nodes[i].preid = i - 1;
  nodes[i].nextid = i + 1;
  }
  nodes[n].nextid = 1;//循环链表,尾指向头
  nodes[1].preid = n;//循环链表,头指向尾
  int now = 1;//从第一个节点开始
  while ((n--) > 1)
  {
  for (int i = 1; i < m; i++)
  {
    now = nodes[now].nextid;
  }
  printf(" %d ", nodes[now].id);
  int prev = nodes[now].preid, next = nodes[now].nextid;
  nodes[prev].nextid = nodes[now].nextid;
  nodes[next].preid = nodes[now].preid;
  now = next;//新的开始
  }
  printf(" %d", nodes[now].nextid);
  return 0;
}


同样的,简图方便大家理解。


e76e6081b3f8799ef670ce22a5412611_e2fbdc74c11b454d98184d7a74df47b9.png


4.一维数组实现单向循环链表


这是最简单的实现方法。定义一个一维数组,数组的第i个节点的i就是节点的值。


#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
int nodes[150];
int main()
{
  int n, m;
  scanf("%d%d", &n, &m);
  for (int i = 1; i <= n - 1; i++)
  {
  nodes[i] = i + 1;//nodes[i]的值就是下一个节点
  }
  nodes[n] = 1;
  int now = 1, prev = 1;
  while ((n--) > 1)
  {
  for (int i = 1; i < m; i++)
  {
    prev = now; now = nodes[now];
  }
  printf(" %d ", now);
  nodes[prev] = nodes[now];//跳过now节点
  now = nodes[prev];//新的now节点
  }
  printf(" %d", now);
  return 0;
}


这个就不画图了。


现在我是在自学c++,还不是很熟练。


总结

 感谢观看,本文到这里就结束了,如果觉得有帮助,请给文章点个赞吧,让更多的人看到。🌹 🌹 🌹

cad3f4971ac28288f5f73c67c1f7b77b_7673ea0a00c3431893891e0c2913a10e.jpeg

 


相关文章
|
2月前
|
负载均衡 算法
ribbon的7种负载均衡算法和替换方法
ribbon的7种负载均衡算法和替换方法
38 0
ribbon的7种负载均衡算法和替换方法
|
2月前
|
算法 索引
【数据结构与算法】5、循环链表、约瑟夫问题、静态链表
【数据结构与算法】5、循环链表、约瑟夫问题、静态链表
39 0
|
2月前
|
机器学习/深度学习 算法 数据可视化
实现机器学习算法时,特征选择是非常重要的一步,你有哪些推荐的方法?
实现机器学习算法时,特征选择是非常重要的一步,你有哪些推荐的方法?
30 1
|
1天前
|
算法 数据安全/隐私保护 计算机视觉
基于二维CS-SCHT变换和LABS方法的水印嵌入和提取算法matlab仿真
该内容包括一个算法的运行展示和详细步骤,使用了MATLAB2022a。算法涉及水印嵌入和提取,利用LAB色彩空间可能用于隐藏水印。水印通过二维CS-SCHT变换、低频系数处理和特定解码策略来提取。代码段展示了水印置乱、图像处理(如噪声、旋转、剪切等攻击)以及水印的逆置乱和提取过程。最后,计算并保存了比特率,用于评估水印的稳健性。
|
3天前
|
算法
【免费】基于SOE算法的多时段随机配电网重构方法
【免费】基于SOE算法的多时段随机配电网重构方法
|
14天前
|
机器学习/深度学习 自然语言处理 算法
深度解析深度学习中的优化算法:从梯度下降到自适应方法
【4月更文挑战第28天】 在深度学习模型训练的复杂数学迷宫中,优化算法是寻找最优权重配置的关键导航者。本文将深入探讨几种主流的优化策略,揭示它们如何引导模型收敛至损失函数的最小值。我们将比较经典的批量梯度下降(BGD)、随机梯度下降(SGD)以及动量概念的引入,进一步探索AdaGrad、RMSProp和Adam等自适应学习率方法的原理与实际应用。通过剖析这些算法的理论基础和性能表现,我们旨在为读者提供一个关于选择合适优化器的参考视角。
|
15天前
|
编解码 算法 数据可视化
【视频】时间序列分类方法:动态时间规整算法DTW和R语言实现
【视频】时间序列分类方法:动态时间规整算法DTW和R语言实现
|
23天前
|
机器学习/深度学习 存储 人工智能
一阶优化算法启发,北大林宙辰团队提出具有万有逼近性质的神经网络架构的设计方法
【4月更文挑战第19天】北京大学林宙辰团队在深度学习领域取得突破,提出基于一阶优化算法的神经网络设计方法,构建具有万有逼近性质的模型,提升训练速度和泛化能力。该方法利用一阶导数信息,高效处理大规模问题。虽然面临非光滑优化和收敛速度挑战,但团队通过正则化和自适应学习率等策略进行改进,相关研究在多个标准数据集上表现出色。
11 1
|
25天前
|
机器学习/深度学习 算法
R语言非参数方法:使用核回归平滑估计和K-NN(K近邻算法)分类预测心脏病数据
R语言非参数方法:使用核回归平滑估计和K-NN(K近邻算法)分类预测心脏病数据
|
1月前
|
存储 算法
从动态规划到贪心算法:最长递增子序列问题的方法全解析
从动态规划到贪心算法:最长递增子序列问题的方法全解析
19 1