请使用合适的数据结构实现:使用“折返报数”方式的Joseph问题。
所谓“折返报数”Joseph问题是指:
(1)n(n>1)个人排成一队,从1到n依次编号;从1到m循环报数,报到m(m>1)者退出;
(2)游戏先从编号为1的人(队头)开始依次从前向后报数,当报数到达队尾时,立即改为从后往前报数;
(3)当从后往前报数到达队头时,立即改为从前往后报数;
(4)如此“折返”报数,直到队列中只剩下1人为止,即为胜者;
要求:
(1)从键盘输入n和m;
(2)依次输出游戏过程中退出人的编号;
(3)输出获胜者编号;
例:
输入:n=5;m=3
输出:
3 4 2 5
胜者:1
#include <iostream>
using namespace std;
typedef struct LinkNode {int data;LinkNode* next;LinkNode* pre;
}*LinkList;
void InitLinkList(LinkList& L) {L = NULL;
}
void CreatRear(LinkList& L,int n) {L = NULL;if (n <= 0)return;else {L = new LinkNode;cin >> L->data;L->pre = NULL; L->next = NULL;if (n > 1) {LinkNode* r = L;for (int i = 1; i < n; i++) {LinkNode* s = new LinkNode;cin >> s->data;r->next = s;s->pre = r;r = r->next;}r->next = NULL;}}
}
void Returning_Joseph(int n, int m) {LinkList L; InitLinkList(L);CreatRear(L, n);LinkNode* p = L; int isBack = 0;for (int i = 0; i < n - 1; i++) {int j = 0;while (j < m - 1) {if (isBack == 0) {while (p->next != NULL && j < m - 1) {p = p->next; j++;}if (p->next == NULL)isBack = 1;}if (isBack == 1) {while (p->pre != NULL && j < m - 1) {p = p->pre; j++;}if (p->pre == NULL)isBack = 0;}}cout << p->data << " ";LinkNode* r = p;if (p->next == NULL || p->pre == NULL) {if (p->next == NULL) {p = p->pre;delete(p->next);}else {p = p->next;delete(p->pre);}}else {p->pre->next = p->next;p->next->pre = p->pre;if (isBack == 0)p = p->next;else p = p->pre;r->next = NULL; r->pre = NULL;delete(r);}}cout << endl;cout << p->data << "是胜者";
}
int main(){Returning_Joseph(5, 3);
}
此题难点在于在约瑟夫问题的基础上摒弃了环的结构,而是改为“折返”,所以自然想到双向链表(无头),但难点在于,如何让程序知道现在是向前遍历还是向后遍历呢?
这里我们设一个初始值 isBack==0,来判断现在是向前还是向后遍历,如果超过了边界,那么更改isBack的值进入到另一个向前遍历的分支即可,如此循环,即可实现“折返”
本文发布于:2024-01-27 20:06:14,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/17063571702356.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |