浅议约瑟夫问题

简介:

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

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

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

结点

翻译成源代码如下:


 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;
                }
            }
            
        }

 循环链表

翻译成源代码如下:


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;
        }

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


List<Node> outList = new List<Node>();
            int index = 0;
            int n = 7;
            uint m = 20;
            List<Node> nodeList = new List<Node>();
            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);
            }

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

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


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

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

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


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


最终运行的结果如下:

②基于位图算法的思想,

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

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


   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的项目时候,也是完全依据这个算法解决的问题,在做一个操作系统调度的时候,也是这个思想.所以,他的实用价值蛮大,所以像腾讯,华为,度娘面试的时候也经常考这个试题或者基于这个试题的变种。



目录
相关文章
|
6天前
|
NoSQL Cloud Native Redis
Redis核心开发者的新征程:阿里云与Valkey社区的技术融合与创新
阿里云瑶池数据库团队后续将持续参与Valkey社区,如过往在Redis社区一样耕耘,为开源社区作出持续贡献。
Redis核心开发者的新征程:阿里云与Valkey社区的技术融合与创新
|
7天前
|
弹性计算 安全 API
访问控制(RAM)|云上安全使用AccessKey的最佳实践
集中管控AK/SK的生命周期,可以极大降低AK/SK管理和使用成本,同时通过加密和轮转的方式,保证AK/SK的安全使用,本次分享为您介绍产品原理,以及具体的使用步骤。
101798 1
|
8天前
|
SQL 关系型数据库 分布式数据库
Doodle Jump — 使用Flutter&Flame开发游戏真不错!
用Flutter&Flame开发游戏是一种什么体验?最近网上冲浪的时候,我偶然发现了一个国外的游戏网站,类似于国内的4399。在浏览时,我遇到了一款经典的小游戏:Doodle Jump...
112727 12
|
11天前
|
SQL 存储 JSON
Flink+Paimon+Hologres 构建实时湖仓数据分析
本文整理自阿里云高级专家喻良,在 Flink Forward Asia 2023 主会场的分享。
71304 1
Flink+Paimon+Hologres 构建实时湖仓数据分析
|
15天前
|
弹性计算 运维 安全
访问控制(RAM)|云上程序使用临时凭证的最佳实践
STS临时访问凭证是阿里云提供的一种临时访问权限管理服务,通过STS获取可以自定义时效和访问权限的临时身份凭证,减少长期访问密钥(AccessKey)泄露的风险。本文将为您介绍产品原理,以及具体的使用步骤。
151041 4
|
13天前
|
数据采集 存储 运维
提升团队工程交付能力,从“看见”工程活动和研发模式开始
本文从统一工程交付的概念模型开始,介绍了如何将应用交付的模式显式地定义出来,并通过工具平台落地。
120146 108
|
14天前
|
监控 负载均衡 Java
深入探究Java微服务架构:Spring Cloud概论
**摘要:** 本文深入探讨了Java微服务架构中的Spring Cloud,解释了微服务架构如何解决传统单体架构的局限性,如松耦合、独立部署、可伸缩性和容错性。Spring Cloud作为一个基于Spring Boot的开源框架,提供了服务注册与发现、负载均衡、断路器、配置中心、API网关等组件,简化了微服务的开发、部署和管理。文章详细介绍了Spring Cloud的核心模块,如Eureka、Ribbon、Hystrix、Config、Zuul和Sleuth,并通过一个电商微服务系统的实战案例展示了如何使用Spring Cloud构建微服务应用。
103516 9
|
15天前
|
人工智能 Serverless 对象存储
让你的文档从静态展示到一键部署可操作验证
通过函数计算的能力让阿里云的文档从静态展示升级为动态可操作验证,用户在文档中单击一键部署可快速完成代码的部署及测试。这一改变已在函数计算的活动沙龙中得到用户的认可。
121074 260
|
14天前
|
Java 数据处理 调度
更高效准确的数据库内部任务调度实践,阿里云数据库SelectDB 内核 Apache Doris 内置 Job Scheduler 的实现与应用
Apache Doris 2.1 引入了内置的 Job Scheduler,旨在解决依赖外部调度系统的问题,提供秒级精确的定时任务管理。