前几天看Linux,无意间看见了这道题目,正好拿来练习一下链表的操作
题意:N个人围成一圈,从1号开始数数,数到M的人退出,问最后剩下来的是谁?
解法一:用双向循环链表
解法二:递推的思想(不过这种方法只能求出最后剩一个人的情况,用循环双向链表能够随意设置还剩几个人)
解法一:双向循环链表
//约瑟夫问题
#include<iostream>
#include<stdio.h>
#include<malloc.h>
using namespace std;
int N,M; //总共有N个人,数到M的人退出
struct Node
{
struct Node *prior;
struct Node *next;
int data;
};
int main()
{
freopen("1.txt","r",stdin);
while(scanf("%d%d",&N,&M)!=EOF)
{
Node *head,*p,*q;
head=(Node*)malloc(sizeof(Node));
//设置头指针
head->data=-1;
head->prior=head;
head->next=head;
p=head;
//加入N个节点
for(int i=1;i<=N;++i)
{
q=(Node*)malloc(sizeof(Node));
q->data=i;
q->next=head;
q->prior=p;
p->next=q;
p=q;
}
int number=0; //记录当前数到几号数字了
int quit_person=0; //退出的人,如果推出的人等于N-1则结束下面的循环
p=head;
Node *before,*present;
while(1)
{
if(quit_person==N-1) //如果已经退出N-1个人了,那么就跳出循环(这边可以调整剩余几个人)
break;
if(p->data==-1)
{
p=p->next;
continue;
}
number++;
present=p; //当前节点
before=p->prior; //当前一个节点的前一个节点
p=p->next; //后面一个节点
//如果数字正好为M,则删除当前这个节点
if(number==M)
{
number=0; //number还原
quit_person++;
before->next=p;
p->prior=before;
free(present);
}
}
//输出剩余的人
p=head->next;
printf("剩余下来的人是:");
while(p!=head)
{
printf("%d ",p->data);
p=p->next;
}
printf("\n");
}
return 0;
}
解法二:
利用递推的思想来解决,不明白这个方法的可以去百度百科查看
//递推求法
#include<iostream>
#include<stdio.h>
using namespace std;
int N,M;
int main()
{
freopen("1.txt","r",stdin);
int s=0;
while(scanf("%d%d",&N,&M)!=EOF)
{
for(int i=2;i<=N;++i)
s=(s+M)%i;
printf("%d\n",s+1);
}
}