约瑟夫问题
一个旅行社要从n名旅客中选出一名幸运旅客,为他提供免费环球旅行服务。方法是,大家站成圈,然后选定一个m,从第1个人开始报数,报到m时,这个人OUT,然后从下一个人开始重新从1报数,重复这个过程,直到最后剩下一个人就是幸运之星。问题就是谁是幸运者呢?
1.数组实现
关键思想:
- 创建一个数组存储旅客的的状态,赋初值为1 , 0表示out。
- 利用i=(i+1)%n,循环遍历数组。
#include <stdio.h>
#include <stdlib.h>
int main() {
int n,m;
int i;
scanf("%d %d",&n,&m);//输入n名旅客,每m个人out。
int *flag = (int*)malloc(n*sizeof(int));//建一个一位数组储存n名n旅客的状态(是否out)
//数组赋初值为1,表示没有out
for(i=0; i<n; i++){
flag[i]=1;
}
int count = 0;//记录出圈人数
int mcount = 0;//记录报数
for(i=0;i<n;i=(i+1)%n){ //i=(i+1)%n实现循环遍历
if(flag[i] == 1){
mcount++;
if(mcount == m){
printf("%d\n",i+1);
count++;
flag[i]=0; //表示out
mcount=0; //报数器归零
}
if(count == n-1){
break;
}
}
}
//查找最后剩下人的编号
for(i=0; i<n; i++){
if(flag[i] == 1){
printf("lucky tourist is %d\n",i+1);
}
}
free(flag);
return 0;
}
2.循环链表实现
#include<stdio.h>
#include<stdlib.h>
typedef struct node{
int data;
struct node *next;
}LinkList;
int Josephus(int n,int m);
int Josephus(int n,int m){
LinkList *L,*r,*s;
L = (LinkList*)malloc(sizeof(LinkList));
r=L;
//尾插法建立有头节点的循环链表
for(int i=1;i<=n;i++){
s=(LinkList*)malloc(sizeof(LinkList));
s->data = i;
r->next = s;
r = s;
}
r->next=L->next;//将尾与头连接
LinkList *p=L->next;
while(p->next!=p){
for(int i=1;i<m-1;i++){
p=p->next;
}
//删除结点
p->next=p->next->next;
p=p->next;
}
return p->data;
}
int main(){
int n,m;
scanf("%d %d",&n,&m);
printf("%d\n",Josephus(n,m));
return 0;
}