名词解释
首先看下,百度百科的解释:(就看简介)https://baike.baidu.com/item/%E7%BA%A6%E7%91%9F%E5%A4%AB%E9%97%AE%E9%A2%98/3857719?fr=aladdin
关于这个问题的求解,大致有以下几个方法。一是模拟整个过程。二是利用数学的方法,先化简问题,再求解。
模拟
利用循环单链表来模拟。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream> //个人喜欢将C/C++的输出混着写。。
using namespace std;
#pragma warning(disable:4996) //不加这句,VS2019对有的C语言函数会报错。。。
typedef struct link_Node
{
int data;
link_Node* next;
}Node, * pNode; //这是数据结构定义。结点抽象成结构体
void outvalue(int m, int n, Node* head) {
while (head->next!=head ) { //循环单链表的判断结束使用这个。
for (int i = 0; i < m-1; i++) {
head = head->next;
}
//cout << head->data<<" "; //如果加了这句话,可以将过程中每次淘汰的那个数字输出。
Node* q = head->next;
head->data = head->next->data;
head->next = head->next->next;
if (q != NULL) {
free(q);
q = NULL;
}
}
cout << head->data;
if (head != NULL) {
free(head);
head = NULL;
}
}
int main()
{
int m, n;
cin >> m >> n;
Node* p = (Node*)malloc(sizeof(Node));
Node* head = p; //这里是在创建循环单链表。
p->data = 1; //我这里是从0开始编号,从1开始报数。
p->next = NULL;
for (int i = 0; i < n-1; i++) {
Node*q= (Node*)malloc(sizeof(Node));
q->data = i + 2;
p->next = q;
p = q;
}
p->next = head; //创建循环单链表
outvalue(m, n, head); //m是倍数,n是总人数。
return 0;
}
这是简单模拟,比较简单易懂。对于单链表的操作细心,别弄错就好。
关于指针,结构体,数组等有疑问的,可以看我前面的分类博客。(生产实习与软通培训)
数学化简再编程
这里就需要先对问题进行适当的分析。
首先,人的编号是 0,1,2,3,4,… 设这道题有n人,倍数是m.
设这道题的解为f(n,m).
那么,第一次出局的那个人的编号是k=(m-1)%n.
设删除一个元素之后,解为f(n-1,m).
这之后,对所有人的编号进行重新排序。(因为游戏规则要求下一次开始时重新数数)
令 k+1---->0 k+2---->1 k+3---->2 …
那么,n-1对应多少?n-1---->n-1-k-1=n-k-2
从而,0---->n-k-1 1---->n-k … k-1---->n-2
接着是最重要的部分了。
取完一个数之后,原序号与新序号的对应关系表达式为:
P(x)=(x-k-1)%n; 原序号---->新序号
那么,Q(x)=(x+k+1)%n; 新序号---->原序号
那么,接着,f(n-1,m)也就是新序号,要用它来推原序号。
则(f(n-1,m)+k+1)%n=(f(n-1,m)+m)%n=f(n,m)为原序号。
即可得出递推公式:(f(n-1,m)+m)%n=f(n,m)。
#include <iostream>
using namespace std;
const int m = 4; //当然这里也可以选择输入
int main()
{
int n, f = 0;
cin >> n;
for (int i = 1; i <= n; i++) f = (f + m) % i;
cout << f << endl;
}
这复杂度一下子降低了太多了。。数学好神奇。这个推到我也是看了好半天才看明白。写的不咋清楚,建议动手算一算清楚些。
约瑟夫问题到此结束。谢谢阅读。