约瑟夫问题:有n只猴子,按顺时针方向围成一圈选大王(编号从1到n),从第1号开始报数,一直数到m,数到m的猴子退出圈外,剩下的猴子再接着从1开始报数。就这样,直到圈内只剩下一只猴子时,这个猴子就是猴王,编程求输入n,m后,输出最后猴王的编号。
样例输入
6 2
样例输出
5
样例输入
12 4
样例输出
1
1.循环链表实现
cpp#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> typedef struct link { int data; link* next; }link; int main() { int n, m; int i; printf("请输入(n/m):"); scanf("%d%d", &n, &m); link* head = (link*)malloc(sizeof(link));//头节点 head->data = -1; head->next = NULL; link* tail, * p, * q; tail = head;//构造循环节点 for (i = 0; i < n; i++) { p = (link*)malloc(sizeof(link)); p->data = i + 1; tail->next = p; p->next = head->next; tail = p; } p = head->next;//p为要删除的那一个指针,q为p的前一个位置的指针 q = tail; i = 1;//用i来报数 while (p != q)//直到两个指针相同时,循环链表内除开头节点外只有一个节点了 { if (i == m)//当报数为m时,删除p,同时让i=1 { i = 1; q->next = p->next; free(p); p = q->next; } else { q = p; p = p->next; i++; } } printf("最后留下的猴子序号为: %d", p->data); free(p); free(head); return 0; }
2.数组标志位实现
cpp#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> int main() { int n, m; int i; int monkey[300] = { 0 }; printf("请输入(n/m): "); scanf("%d%d", &n, &m); for (i = 0; i < n; i++) { monkey[i] = i + 1; } int number = n;//记录此时数组中有效元素的个数 int count = 1;//用来报数 int pos = 0;//记录数组下标位置 while (number > 1) { if (monkey[pos] > 0) { if (count == m) { monkey[pos] = 0; count = 1; number--; pos = (pos + 1) % n; } else { count++; pos = (pos + 1) % n; } } else pos = (pos + 1) % n; } for (i = 0; i < n; i++) if (monkey[i] > 0) printf("最后留下的猴子序号为:%d\n", monkey[i]); return 0; }
3.数组模拟(循环)链表实现
cpp#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> int main() { int n, m; int monkey[300] = { 0 }; int i; printf("请输入(n/m): "); scanf("%d%d", &n, &m); for (i = 0; i < n - 1; i++)//数组模拟循环链表,数组的值相当于链表的next,指向下一个数组结点的下标 { monkey[i] = i + 1; } monkey[i] = 0; int number = n;//记录当前数组有效元素个数 int count = 1;//用来报数 int pos = 0; int prior = n - 1; while (number > 1)//或者while(prior!=pos) { if (count != m) { count++; prior = pos; pos = monkey[pos]; } else { monkey[prior] = monkey[pos]; monkey[pos] = -1; pos = monkey[prior]; count = 1; number--; } } printf("最后留下的猴子序号为:%d\n", pos + 1); return 0; }
4.数学方法(原理自己百度查)
cpp#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> int main() { int n, m; printf("请输入(n/m):"); scanf("%d%d", &n, &m); int pos = 0; for (int i = 2; i < n + 1; i++) { pos = (pos + m) % i; } printf("最后留下的猴子序号为:%d\n", pos + 1); return 0; }