我们先明确什么是约瑟夫问题:
n个人围成一圈,初始编号从1~n排列,从约定编号为x的人(通常x为1)开始报数,数到第m个人出圈,接着又从1开始报数,报到第m个数的人又退出圈,以此类推,最后圈内只剩下一个人,这个人就是赢家,求出赢家的编号。
如果我们用链表来做,那么相信已经有了思路:正序建表,删除链表中的元素。
原题链接:约瑟夫问题
代码:
#include <stdio.h>
#include <stdlib.h>
struct node
{int id;struct node* next;
};
struct node* creat(int n);//循环链表建立函数;
struct node* search(struct node* head, int m);//查找胜利者的函数;
int main()
{int n, m;struct node* head, * q;scanf("%d%d", &n, &m);head = creat(n);//调用链表建立函数建立链表;q = search(head, m);//查找胜利者节点;printf("%d\n", q->id);//输出;return 0;
}
struct node* creat(int n)//建立顺序链表再将最后一个节点的指针指向头结点;
{struct node* p, * q, * head;head = (struct node*)malloc(sizeof(struct node));head->next = NULL;head->id = 1;q = head;int i;for (i = 2; i <= n; i++){p = (struct node*)malloc(sizeof(struct node));p->next = NULL;p->id = i;q->next = p;q = p;}q->next = head;return(head);
}
struct node* search(struct node* head, int m)
{struct node* p;p = head;int num = 0;while (p->next != p)//循环结束的条件为链表只剩下一个节点;{num++;if (num % (m - 1) == 0)//要注意m-1的括号不要遗漏;{p->next = p->next->next;//删除节点;p = p->next;//也为当删除节点时p指针并未移动,所以要移动到下一个节点,//下一次要从下一个节点开始数;}else p = p->next;}return(p);
}
第二种方法就是用数组来模拟
#include<iostream>
using namespace std;
#define N 100
int main() {int n, m, s = 1;//n:总人数,m:报数值,s报数人的起始编号 cin >> n >> m;int a[N] = { 0 };//数组初始化int i, j;for (i = 1; i <= n; i++) {a[i] = i; //i是数组的位置量,a[i]是每个人的原始编号(从1开始) }i = 0; //数组的起点(0) while (n > 1) {i = (i + m - 1) % n; //出圈的人在数组中的位置 for (j = i + 1; j < n; j++){a[j - 1] = a[j];}n--; //出局1人后,总人数-1 if (i == n) //终点后,开始起点(围成一个圈) {i = 0;}}cout<<a[i];//输出留下的人的原始编号 return 0;
}