标题
题目描述:
编号为1…N的N个小朋友玩游戏,他们按编号顺时针围成一圈,从第一个人开始按逆时针次序报数,报到第M个人出列;然后再从下个人开始按顺时针次序报数,报到第K个人出列;再从下一个人开始按逆时针次序报数,报到第M个人出列;再从下个人开始按顺时针次序报数,报到第K个人出列……以此类推不断循环,直至最后一人出列。请编写程序按顺序输出出列人的编号。
输入格式:
输入为3个正整数,分别表示N、M、K,均不超过1000。
输出格式:
输出为一行整数,为出列人的编号。每个整数后一个空格。
样例:
输入样例:
6 3 5
输出样例:
5 3 1 2 4 6
思路:
约瑟夫问题,是一个计算机科学和数学中的问题,在计算机编程的算法中,类似问题又称为约瑟夫环,又称“丢手绢问题”。“猴子选大王”问题就是经典的约瑟夫问题。度娘详解
本题目为特殊约瑟夫问题,主要特殊在,每出列一个人后,报数方向逆置。本题在实际实现中就是一个典型的模拟问题。在存储上使用循环双向链表将会更加直观易懂。但是需要注意对在对链表进行操作时,指针的改变需要格外注意。
代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
struct peo{
int num;
struct peo *ss;//顺时针
struct peo *ns;//逆时针
};
typedef struct peo* ptrtopeo;
int main(){
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
ptrtopeo head = (ptrtopeo)malloc(sizeof(struct peo));
head->num = 1;
head->ss = NULL;
head->ns = NULL;
ptrtopeo tail,ptr;
tail = head;
int count = 2;
while(count <= n){
ptr = (ptrtopeo)malloc(sizeof(struct peo));
ptr->num = count;
ptr->ns = tail;
ptr->ss = NULL;
tail->ss = ptr;
tail = ptr;
count++;
}
// printf("-------------------------------1\n");
tail->ss = head;
head->ns = tail;
count = n;
ptr = head;
ptrtopeo ptr1,ptr2,h;
int p = 1;
while(count > 1){
while(p < m){
ptr = ptr->ns;
p++;
}
printf("%d ",ptr->num);
ptr1 = ptr->ns;
ptr2 = ptr->ss;
ptr1->ss = ptr2;
ptr2->ns = ptr1;
h = ptr;
ptr = ptr->ns;
free(h);
count--;
p = 1;
if(count == 1) break;
while(p < k){
ptr = ptr->ss;
p++;
}
printf("%d ",ptr->num);
ptr1 = ptr->ns;
ptr2 = ptr->ss;
ptr1->ss = ptr2;
ptr2->ns = ptr1;
h = ptr;
ptr = ptr->ss;
free(h);
count--;
p = 1;
}
printf("%d ",ptr->num);
free(ptr);
return 0;
}