8,约瑟夫斯(Josephus)问题

  据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。
  然而Josephus 和他的朋友并不想遵从,Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。
实现思路:
1)利用环形链表模拟,出列表示自杀。
2)First指正移到开始数数位置,辅助指针helpPointer移到First前一个位置,也就三环形链表末尾 helpPointer.Next=First
3)开始数数,First = First.Next helpPointer = helpPointer.Next; 两个指针一起移动,First指向哪个节点出列
4)First == First.Next 表示已有一个元素
C#代码实现:
  1 using System;
  2 using System.Collections.Generic;
  3 using System.Text;
  4 
  5 namespace 数据结构
  6 {
  7     public class CircleLinked
  8     {
  9         //创建头指针
 10         private Node First { get; set; }
 11         //创建环形链表
 12         public void Add(int nums)
 13         {
 14             if (nums < 1)
 15             {
 16                 Console.WriteLine("至少需要一个节点");
 17                 return;
 18             }
 19             //创建辅助指针
 20             Node curNode = null;
 21             for (int n = 1; n <= nums; n++)
 22             {
 23                 Node node = new Node(n);
 24                 if (n == 1)
 25                 {
 26                     //First和curNode指针指向第一节点
 27                     First = node;
 28                     curNode = First;
 29                     //指向自己形成环路
 30                     curNode.Next = First;
 31                     continue;
 32                 }
 33                 //上一节点断开环路,Next指向下一节点
 34                 curNode.Next = node;
 35                 //curNode指针移指向下一节点
 36                 curNode = node;
 37                 //指向第一个节点,形成环路
 38                 curNode.Next = First;
 39             }
 40         }
 41 
 42         //打印环形链表
 43         public void Scan()
 44         {
 45             if (First == null)
 46             {
 47                 Console.WriteLine("空链表");
 48             }
 49             //创建辅助指针
 50             var curNode = First;
 51             while (true)
 52             {
 53                 Console.Write($"{curNode.No}\t");
 54                 //如果Next地址三First说明已经到最后一个
 55                 if (curNode.Next == First)
 56                 {
 57                     break;
 58                 }
 59                 curNode = curNode.Next;
 60             }
 61         }
 62 
 63         /// <summary>
 64         /// 
 65         /// </summary>
 66         /// <param name="startNo">开始位置</param>
 67         /// <param name="countNums">数多少次</param>
 68         /// <param name="nums">数多少次</param>
 69         public void Josephus(int startNo, int countNums, int nums)
 70         {
 71             if (First == null || startNo < 1 || startNo > nums)
 72             {
 73                 Console.WriteLine("参数错误");
 74                 return;
 75             }
 76             //只有一个节点,直接输出
 77             if (First.Next == First)
 78             {
 79                 Console.WriteLine($"{First.No}");
 80                 return;
 81             }
 82             //辅助指针
 83             Node helpPointer = First;
 84             //First移到开始位置
 85             while (true)
 86             {
 87                 if (First.No == startNo)
 88                 {
 89                     break;
 90                 }
 91                 First = First.Next;
 92             }
 93             //辅助helpPointer指针移动到链表末尾
 94             while (true)
 95             {
 96                 if (helpPointer.Next == First)
 97                 {
 98                     break;
 99                 }
100                 helpPointer = helpPointer.Next;
101             }
102             //出列
103             bool flag = true;
104             while (flag)
105             {
106                 //只剩下一个节点
107                 if (First.Next == First)
108                 {
109                     flag = false;
110                 }
111                 else
112                 {
113                     //数数
114                     for (int n = 1; n < countNums; n++)
115                     {
116                         First = First.Next;
117                         helpPointer = helpPointer.Next;
118                     }
119                 }
120                 //First指向的节点出列
121                 Console.Write($"{First.No}\t");
122                 if (flag)
123                 {
124                     First = First.Next;
125                     helpPointer.Next = First;
126                 }
127             }
128         }
129 
130 
131         public class Node
132         {
133             public int No { get; set; }
134             public Node Next { get; set; }
135             public Node(int no)
136             {
137                 this.No = no;
138             }
139         }
140     }
141 
142     public class Josephus
143     {
144         public static void Main(string[] args)
145         {
146             var circle = new CircleLinked();
147             Console.WriteLine("加入41个人");
148             circle.Add(41);
149             circle.Scan();
150             Console.WriteLine("\n自杀顺序,最后两个个幸存");
151             circle.Josephus(1, 3, 41);
152         }
153     }
154 }
posted @ 2020-04-15 01:30  小橘·Huang  阅读(311)  评论(0编辑  收藏  举报