求帮忙,C语言约瑟夫环算法

题意是这样的:

n个人排成一圈,依次编号1~n,从第k个人开始,从1依次往下数,数到m的人出列,
然后又从下一个人从1开始,数到m的人又出列,这样依次进行游戏,直到最后一个人出列。

我想了好几天了没写出来,求大家帮帮忙。
这里我给出了一部分代码:
#include <stdio.h>
#include <stdlib.h>
// 定义一个存储链表的结构体
typedef struct node {
    int data;
    struct node *next;
} Node;

Node *circle_create(int n);
void count_off(Node *head, int n, int k, int m);

int main() {
    int n, k, m;
    scanf("%d %d %d", &n, &k, &m);
    Node *head = circle_create(n);
    count_off(head, n, k, m);
    return 0;
}

// 创建循环链表的方法
Node *circle_create(int n) {
    Node *temp, *new_node, *head;
    int i;
    // 创建第一个链表节点并加数据
    temp = (Node *) malloc(sizeof(Node));
    head = temp;
    head->data = 1;
    // 创建第 2 到第 n 个链表节点并加数据
    for(i = 2; i <= n; i++) {
        new_node = (Node *) malloc(sizeof(Node));
        new_node->data = i;
        temp->next = new_node;
        temp = new_node;
    }
    temp->next = head;

    return head;
}
// 现在进行约瑟夫环的算法
void count_off(Node *head, int n, int k, int m) {
    
}
阅读 3k
2 个回答

这是一个数学问题,求解最后只剩一个人时在原队伍排的位置,从1~n计数,查看维基百科有详细的代码解答约瑟夫问题。另外,在微软的hihocoder平台上也有对该问题的小规模、大规模的完全解答,可以注册账号练一下,解答都给出了完整的伪代码:第九十四周 约瑟夫问题

第一次遇见这个问题会用模拟求解,大一时用数组模拟,用0代表该位置的人被杀掉,非0代表还存活,每次自增为i = (i + 1) % n,这样编码比起链表更为简单一点,示例如下:

    bool survivor[1005];
    int cnt = n;
    memset(survivor, true, sizeof(survivor));

   for (int i = 0, j = 1; cnt > 0; i = (i + 1) % n) {
    if (!survivor[i])
        continue;
    if (cnt == 1)
        printf("%d\n", i);
    if (j == 0) {
        survivor[i] = false;
        cnt --;
    }
    j = (j + 1) % m;
}

如果要用链表模拟,首先要是个循环链表,而且要实现正确的删除元素。既然要找到最后存活的人,要对链表数目计数,在count为1的时候,把最后编号输出。

这道问题的详尽解答在第九十四周 约瑟夫问题上有,需要考虑到n很大时的情况,n < m时的情况。至于从k个人开始点人,与原问题应该等价,求出最终编号后(ans + k) % n即可。C语言中数组从0开始,输出答案要注意一下。

希望对你有所帮助。

约瑟夫环问题

这是我归纳出来的约瑟夫环所有的解答,包括用循环链表,递归,线段树等等。

推荐问题
宣传栏