博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
浅议约瑟夫问题
阅读量:5305 次
发布时间:2019-06-14

本文共 6505 字,大约阅读时间需要 21 分钟。

什么是约瑟夫问题,约瑟夫问题是据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到留下一个人都自杀身亡为止。

解决这个问题,有多少种方法。

①最常用的方法是使用循环链表的解决。首先, 将这39 个犹太人构成一个循环链表,每个犹太人等同与一个结点,这个结点有后继结点相连,最后的结点与第一个结点相连。我实现的思路如下所示:

结点

翻译成源代码如下:

View Code
public class Node        {            private Node preNode;            private Node nextNode;            private int id;            private uint password;            public Node PreNode            {                get {                    return preNode;                }                set {                    preNode = value;                }            }            public Node NextNode {                get {                    return nextNode;                }                set {                    nextNode = value;                }            }            public int ID            {                get {                    return id;                }                set {                    id = value;                }            }            public uint Password            {                get {                    return password;                }                set {                    password = value;                }            }                    }

 循环链表

翻译成源代码如下:

View Code
private Node firstNode = null;        private Node lastNode=null;        private Node nextNode = null;        private int count = 0;               public int Count        {            get {                return count;            }            set {                count = value;            }        }        public Circle()        {                 }        public void Add(int id,uint password)        {            count++;             Node node = new Node();             node.ID = id;             node.Password = password;             this.Add(node);        }        public void Add(int id)        {            count++;            Node node = new Node();            node.ID = id;            this.Add(node);                    }        private void Add(Node node)        {            if (firstNode == null)            {                firstNode = node;                lastNode = firstNode;                lastNode.NextNode = firstNode;                lastNode.PreNode = firstNode;                firstNode.NextNode = lastNode;                firstNode.PreNode = lastNode;            }            else            {                lastNode.NextNode = node;                node.PreNode = lastNode;                node.NextNode = firstNode;                firstNode.PreNode = node;                lastNode = node;            }        }        public Node NextNode()        {            Node node=new Node();            if (nextNode == null)            {                node = firstNode;                nextNode = firstNode.NextNode;                           }            else            {                node = nextNode;                nextNode = node.NextNode;            }            return node;        }        public void RemoveNode(Node node)        {            count--;            Node _preNode = node.PreNode;            Node _nextNode = node.NextNode;            _preNode.NextNode = _nextNode;            _nextNode.PreNode = _preNode;        }

把每个循环链表初始化,相应的源代码如下:

View Code
List
outList = new List
(); int index = 0; int n = 7; uint m = 20; List
nodeList = new List
(); Node nd = new Node(); nd.ID = 1; nd.Password = 3; nodeList.Add(nd); nd = new Circle.Node(); nd.ID = 2; nd.Password = 1; nodeList.Add(nd); nd = new Circle.Node(); nd.ID = 3; nd.Password = 7; nodeList.Add(nd); nd = new Circle.Node(); nd.ID = 4; nd.Password = 2; nodeList.Add(nd); nd = new Circle.Node(); nd.ID = 5; nd.Password = 4; nodeList.Add(nd); nd = new Circle.Node(); nd.ID = 6; nd.Password = 8; nodeList.Add(nd); nd = new Circle.Node(); nd.ID = 7; nd.Password = 4; nodeList.Add(nd); Circle c = new Circle(); foreach (Node node in nodeList) { c.Add(node.ID, node.Password); }

  这是把所有的数据添加到泛型数组中。

 在进行点名,出列。相应的源代码如下:

View Code
while (c.Count > 0)            {                index++;                nd = c.NextNode();                if (index == m)                {                    c.RemoveNode(nd);                    outList.Add(nd);                    index = 0;                    m = nd.Password;                }            }

也是放入新的泛型数组中去。

把所显示的结果最终显示的源代码:

View Code
foreach (Circle.Node node in outList)            {                Console.WriteLine(node.ID);            }

最终运行的结果如下:

②基于位图算法的思想,

这里做法是建立一个数组来存储相应的数据,建立一个布尔变量来编辑是不是是不是进行了出列的标志,没出列一次,把相应的布尔的变量就置为假,一次循环操作,直到满足题意。这就基本思路,相应的流程图如下:

那实现的源代码就非常简单了,①对数据进行赋值的数组,一个布尔变量标记的数组。②判断布尔变量只有一个为真的方法。③依次报数,当报到相应的数字就进行了出列。④相应的索引大于数列的总长度又归零,直到布尔数组中一个为真的方法。源代码如下:

View Code
public static bool CheckArray(bool[] array)        {            int temp = 0;            for (int i = 0; i < array.Length; i++)            {                if (array[i])                {                    temp++;                }            }            return temp == 1;        }            int[] array = new int[M];            ;            bool[] blarray = new bool[M];            for (int i = 0; i < M; i++)            {                array[i] = (i + 1);                blarray[i] = true;            }            int count = 0;            int index = 0;            while (!CheckArray(blarray))            {                if (blarray[index])                {                    count++;                }                if (count == N)                {                    Console.WriteLine("数字" + array[index] + "出列");                    count = 0;                    blarray[index] = false;                }                index++;                if (index == M)                {                    index = 0;                }            }

运行结果如下:

两种方法互有千秋。比较如下:

2

这就是我对约瑟夫环问题的一点点心得,请大家多多指教。

协后感,不要看这个算法,我以前在做一个callcenter的项目时候,也是完全依据这个算法解决的问题,在做一个操作系统调度的时候,也是这个思想.所以,他的实用价值蛮大,所以像腾讯,华为,度娘面试的时候也经常考这个试题或者基于这个试题的变种。

转载于:https://www.cnblogs.com/manuosex/archive/2012/11/23/2784134.html

你可能感兴趣的文章
把word文档中的所有图片导出
查看>>
浏览器的判断;
查看>>
ubuntu 18.04取消自动锁屏以及设置键盘快捷锁屏
查看>>
Leetcode 589. N-ary Tree Preorder Traversal
查看>>
机器学习/深度学习/其他开发环境搭建记录
查看>>
xml.exist() 实例演示
查看>>
判断是否为空然后赋值
查看>>
zabbix监控日志文件
查看>>
正则表达式
查看>>
pip install torch on windows, and the 'from torch._C import * ImportError: DLL load failed:' s...
查看>>
环套树
查看>>
java基础(一):我对java的三个环境变量的简单理解和配置
查看>>
arcgis api 4.x for js 结合 Echarts4 实现散点图效果(附源码下载)
查看>>
YTU 2625: B 构造函数和析构函数
查看>>
apache自带压力测试工具ab的使用及解析
查看>>
C#使用Xamarin开发可移植移动应用(2.Xamarin.Forms布局,本篇很长,注意)附源码
查看>>
jenkins搭建
查看>>
C#中使用Split分隔字符串的技巧
查看>>
eclipse的调试方法的简单介绍
查看>>
加固linux
查看>>