约瑟夫(环)问题

名词解释

首先看下,百度百科的解释:(就看简介)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;
}

这复杂度一下子降低了太多了。。数学好神奇。这个推到我也是看了好半天才看明白。写的不咋清楚,建议动手算一算清楚些。
约瑟夫问题到此结束。谢谢阅读。

发布了27 篇原创文章 · 获赞 0 · 访问量 425

猜你喜欢

转载自blog.csdn.net/weixin_40007143/article/details/103773479