约瑟夫问题 (洛谷P1996)

约瑟夫问题

题目描述

n n n 个人围成一圈,从第一个人开始报数,数到 m m m 的人出列,再由下一个人重新从 1 1 1 开始报数,数到 m m m 的人再出圈,依次类推,直到所有的人都出圈,请输出依次出圈人的编号。

注意:本题和《深入浅出-基础篇》上例题的表述稍有不同。书上表述是给出淘汰 n − 1 n-1 n1 名小朋友,而该题是全部出圈。

输入格式

输入两个整数 n , m n,m n,m

输出格式

输出一行 n n n 个整数,按顺序输出每个出圈人的编号。

样例 #1

样例输入 #1

10 3

样例输出 #1

3 6 9 2 7 1 8 5 10 4

提示

1 ≤ m , n ≤ 100 1 \le m, n \le 100 1m,n100

代码

1. 动态链表

#include <iostream>
using std::cin, std::cout;
struct node {
    int data;       // 节点的值
    node * next;   // 指向下一个节点
};
int main() {
	int n, m;		 // n为人数,m为出列的人报的数
    cin >> n >> m;
    node *head,      // head指向链表的头部
         *pnew,      // pnew用于创建新的节点
         *current,   // current指向当前的节点
         *prev;      // prev指向当前节点的上一个节点
    // 初始化链表头
    head = new node; head->data = 1; head->next = NULL;
    current = head; // 让当前节点指向链表头(同时也是尾节点)
    for (int i = 2; i <= n; i++) { // 初始化链表
        // 初始化新节点pnew
        pnew = new node; pnew->data = i; pnew->next = NULL;
        // 把pnew载入链表,并且更新当前指针指向新节点(尾节点)
        current->next = pnew;   current = pnew;
    }
    current->next = head; // 构建循环链表

    current = head; 	  // 让当前节点指向链表头(从头开始遍历链表)
    while (n-- > 1) { 				  // 直到链表节点只剩一个为止
        for (int i = 1; i < m; i++) { // 找到第m个人
            prev = current;           // prev指向current更新前的节点
            current = current->next;  // 更新current
        }
        cout << current->data << " ";    // 输出第m个节点和空格
        prev->next = current->next;     // 跳过当前第m个节点
        delete current;                 // 删除第m个节点
        current = prev->next;           // 开始新的一轮报数
    }
    cout << current->data;  // 输出最后一个节点
    delete current;         // 删除最后一个节点
    return 0;
}

2. 静态链表(使用结构体数组实现)

#include <iostream>
using std::cin, std::cout;
const int ListSize = 105; // 链表的长度
struct node {
    int id;       		  // 节点的编号
    int nextid;  		  // 指向下一个节点的索引
} list[ListSize];
int main() {
    int n, m;     		  // n为人数,m为出列的人报的数
    cin >> n >> m;
    for (int i = 1; i <= n; i++) { // 初始化链表
        list[i].id = i;            // 节点的编号为i
        list[i].nextid = i + 1;    // 下一个节点的索引为i + 1
    }
    list[n].nextid = 1;        // 构成循环链表
    // current是当前节点的编号,prev是上一个节点的编号
    int current = 1, prev = 1;
    while (n-- > 1) {          // 直到链表节点只剩一个为止
        for (int i = 1; i < m; i++) {       // 找到第m个人
            prev = current;                 // prev保存上一个节点的编号
            current = list[current].nextid; // 更新current到下一个节点
        }
        cout << list[current].id << " ";            // 输出编号和空格
        list[prev].nextid = list[current].nextid;   // 跳过当前节点
        current = list[prev].nextid;                // 开始新一轮报数
    }
    cout << list[current].id;  // 输出最后一个节点的值
    return 0;
}

3. 静态链表(用一维数组实现)

#include <iostream>
using std::cin, std::cout;
const int ListSize = 105;
int list[ListSize];   // 链表的长度
int main() {
    int n, m;         // n为人数,m为出列的人报的数
    cin >> n >> m;
    for (int i = 1; i <= n - 1; i++) {
        list[i] = i + 1;
    }
    list[n] = 1; 	  // 构成循环链表
    // current是当前节点的编号,prev是上一个节点的编号
    int current = 1, prev = 1;
    while (n-- > 1) {                  // 直到链表节点只剩一个为止
        for (int i = 1; i < m; i++) {  // 找到第m个人
            prev = current;            // prev保存上一个节点的编号
            current = list[current];   // 更新current到下一个节点
        }
        cout << current << " ";        // 输出编号和空格
        list[prev] = list[current];    // 跳过当前节点
        current = list[prev];          // 开始新一轮报数
    }
    cout << current;  // 输出最后一个节点的值
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值