C++ 用循環鏈表解決約瑟夫環問題


約瑟夫環問題

    已知 n 個人(n>=1)圍坐一圓桌周圍,從 1 開始順序編號,從序號為 1 的人開始報數,順時針數到 m 的那個人出列。下一個人又從 1 開始報數,數到m 的那個人又出列。依此規則重復下去,直到所有人全部出列。請問最后一個出列的人的初始編號。

 

要求

    輸入人數 n,所報數 m,輸出最后一個人的初始編號。

 

解決思路

  • 首先因為是圓桌問題,使用鏈表解決的話需要構建循環鏈表。
  • 接着是出列問題,這里我的設計思路是將指向鏈表的指針移動到需要出列的人的位置,然后根據正常的鏈表刪除進行操作即可。
  • 最后是類的設計,可以將 head 、 m、 n、鏈表構建、鏈表刪除等整合到一起進行封裝。

 

代碼

  1 // 6.cpp -- using gcc compiler 
  2 #include <iostream>
  3 using namespace std;
  4 
  5 typedef struct List
  6 {
  7     int num;
  8     struct List *next;
  9 }*pList;
 10 
 11 class Josephus
 12 {
 13     public:
 14         Josephus() {}
 15         Josephus(int number, int mes):
 16             n(number),
 17             m(mes){}
 18         void set();
 19         void creat();
 20         void del();
 21     private:
 22         pList head;
 23         int n, m, tmp_n;
 24 };
 25 
 26 void Josephus::set()
 27 {
 28     cout << "please input the number of the people: ";
 29     cin >> n;
 30     tmp_n = n;
 31     cout << "please input the m: ";
 32     cin >> m;
 33 }
 34 
 35 void Josephus::creat()
 36 {
 37     pList p1, p2;
 38     pList p = new List;
 39     n += 1;
 40     p -> num = 1;
 41     p2 = head = p;
 42     for(int i = 2; i < n; i++)
 43     {
 44         p = new List;
 45         p -> num = i;
 46 
 47         p1 = p2;
 48         p2 = p;
 49         p1 -> next = p2;
 50     }
 51 
 52     p2 -> next = head;
 53     // output each number of the circle list's members.
 54     // and it should be: 1, 2, ..., n
 55     p = head;
 56     cout << "Now, the \"num\" member of the list is: " << endl;
 57     while(n--)
 58     {
 59         if(n == 0)
 60             cout << p-> num << ".";
 61         else
 62         {
 63             cout << p->num << ", ";
 64             p = p -> next;
 65         }
 66     }
 67 }
 68 
 69 void Josephus::del()
 70 {
 71     pList p1 = NULL;
 72     pList p2 = head;
 73 
 74     n = tmp_n + 1;
 75     while(n--)
 76     {
 77         int s = m - 1;
 78         while(s--)
 79         {
 80             p1 = p2;
 81             p2 = p2 -> next;
 82         }
 83         
 84         if(n == 0)
 85         {
 86             p2 = p2 -> next;
 87             p1 -> next = NULL;
 88             cout << "The result is: " << p2 -> num << endl;
 89         }
 90         else 
 91         {
 92             p2 = p2 -> next;
 93             p1 -> next = p2;
 94         }
 95     }
 96 }
 97 
 98 int main()
 99 {
100     Josephus t;
101     t.set();
102     t.creat();
103     cout << endl;
104     t.del();
105     return 0;
106 }

 

代碼解析

    5-9行定義了鏈表的結構,其中 num就是初始編號

    23行的 tmp_n 負責記錄 n 的初始值

    75行開始進行循環,共循環 n+1 次,每次都將 p2 移動到需要被排除的人的位置。

    n=0時為最后一次循環,此時p1、p2都指向最后一個人,輸出 num。

    n!=0則去掉p2指向的節點,開始下一次循環。

 

解決約瑟夫環問題的關鍵在於去掉計數為 m 的那個人,並從他之后開始重新計數。

而以上的解決方案巧妙的利用了循環鏈表來解決問題。因為對鏈表的了解不算深入,所以暫時還想不出更好的解決方案。

 

總結

解決鏈表問題的關鍵在於對鏈表的構建以及其他操作,而鏈表的問題只靠想象是不可能的解決的,最好還是自己動手畫圖,這樣一切都會變得清晰明了,問題也會迎刃而解。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM