问题描述:约瑟夫问题:有n只猴子,按顺时针方向围成一圈选大王(编号从1到n),从第1号开始报数,一直数到m,数到m的猴子退出圈外,剩下的猴子再接着从1开始报数。就这样,直到圈内只剩下一只猴子时,这个猴子就是猴王,编程求输入n,m后,输出最后猴王的编号。
关于输入:每行是用空格分开的两个整数,第一个是 n, 第二个是 m ( 0 < m,n <=300)。最后一行是:
0 0
关于输出:对于每行输入数据(最后一行除外),输出数据也是一行,即最后猴王的编号。
例子输入:
6 2
12 4
8 3
0 0
例子输出:
5
1
7
提示:所给的数据中,m 未必比 n 小!
解题思路:使用链表。
- #include <iostream>
- #include <vector>
- using namespace std;
- class JosLink;
- class LinkNode;
- //定义链表结点
- class LinkNode
- {
- friend class JosLink;
- public:
- LinkNode(int info, LinkNode* nextValue = NULL)
- {
- data = info;
- next = nextValue;
- }
- public:
- int data; //用于保存结点元素的内容
- LinkNode *next; //指向后继结点的指针
- };
- //定义约瑟夫链表(循环链表)
- class JosList
- {
- public:
- //构造函数
- JosList(int n){ InitList(n); }
- //析构函数
- ~JosList();
- //初始化包含n个猴的链表
- bool InitList(int n);
- //删除头节点指向的下一个节点
- bool eraseNode(LinkNode *L);
- public:
- LinkNode *head, *current, *tail;
- };
- bool JosList::InitList(int n)
- {
- if( n<1 ) return false;
- head = new LinkNode(1);
- if( n==1 )
- {
- head->next = head;
- return true;
- }
- for(int i=2; i<=n; i++)
- {
- current=new LinkNode(i);
- if(i==2)
- {
- head->next = current;
- tail = current;
- }
- else
- {
- tail->next = current;
- tail = current;
- }
- }
- current->next = head; //做成循环链表
- return true;
- }
- bool JosList::eraseNode(LinkNode *L)
- {
- LinkNode* current = L->next;
- if(current==L)
- return false;
- L->next = current->next;
- return true;
- }
- int main()
- {
- int n, m;
- vector<int> output;
- while( cin>>n>>m && n && m )
- {
- bool flag = true;
- JosList* jList = new JosList(n);
- if(m==1)
- output.push_back(n);
- else
- {
- while(flag)
- {
- for(int i = 1; i < m-1; i++)
- jList->head = jList->head->next;
- flag = jList->eraseNode(jList->head);
- jList->head = jList->head->next;
- }
- output.push_back(jList->head->data);
- }
- }
- for(vector<int>::size_type i = 0; i < output.size(); i++)
- {
- cout<<output[i]<<endl;
- }
- system("pause");
- return 0;
- }