问题描述: 约瑟夫问题的一种描述是:编号为1,2,3~n的n个人按顺时针方向围坐一圈,没人持有一个密码(正整数),开始时任选一个整数作为报数上限值m, 从第一个人开始顺时针自1开始数序报数,报道m时停止报数。报m的人出列,将他的密码作为新的m值,从他顺时针的方向上下一个人开始重新从1报数,如此下去,直至所有的人全部出列为止。设计一个程序,求出出列顺序。 利用单向循环列表作为存储结构模拟过程,按照出列顺序打印出个人的编号。 例如:m的初始值为20,n=7,7个人的密码分别是3,1,7,2,4,8,4,出列的顺序为6,1,4,7,2,3,5.
解题思路: 1.利用m=m%n,进行求余计算,然后遍历到此节点的前一个结点,进行删除操作 2.每次输出后更改m和n的值 3.结束的条件
#include<iostream>
using namespace std;
struct ListNode
{
int number;
int password;
struct ListNode* next;
};
struct ListNode* readList(int n)
{
struct ListNode* head = NULL, * last = NULL, * p;
int temp;
int a = n;
for (int i = 1; i <= a; i++)
{
scanf_s("%d", &temp);
p = (struct ListNode*)malloc(sizeof(struct ListNode));
p->number = i;
p->password = temp;
p->next = NULL;
if (head == NULL)
head = p;
else last->next = p;
last = p;
}
last->next = head;
return head;
}
int main()
{
int m, n;
struct ListNode* L;
printf("请输入m和n的值");
scanf_s("%d %d",&m,&n);
printf( "请依次输入每个人的密码:");
L = readList(n);
while (n)
{
struct ListNode* temp;
m = m % n;
for (int i = 1; i < m - 1; i++)
{
L = L->next;
}
temp = L->next;
L->next = temp->next;
printf("%d", temp->number);
n--;
m = temp->password;
if (n != 0)
{
if (m % n != 1)
{
L = L->next;
}
}
free(temp);
}
return 0;
}
|