您的位置:首页 > 编程语言 > C语言/C++

约瑟夫问题(链表经典)

2016-11-22 16:49 141 查看

约瑟夫问题

总时间限制: 1000ms内存限制: 65536kB 
描述 
约瑟夫问题:有n只猴子,按顺时针方向围成一圈选大王(编号从1到n),从第1号开始报数,一直数到m,数到m的猴子退出圈外,剩下的猴子再接着从1开始报数。就这样,直到圈内只剩下一只猴子时,这个猴子就是猴王,编程求输入n,m后,输出最后猴王的编号。
输入 
每行是用空格分开的两个整数,第一个是 n,第二个是 m ( 0 < m,n <=300)。最后一行是:0

输出 
对于每行输入数据(最后一行除外),输出数据也是一行,即最后猴王的编号 
样例输入 

6 2 

12 4 

8 3 

0 0 
样例输出 





7
解析:这是一个很经典(经典就代表这道题是围绕着链表的核心展开)的链表问题,当然也可以不用链表来做。

首先要注意几点:

1.题目的要求是要围成一个圈,所以要有一点技巧处理:将最后一个的下一个指向第一个

2.每次踢出一个猴砸之后,都是从踢出的那个猴砸的下一个开始,而不是重新从第一个开始。(当时我就是因为这里理解错了一直没做出来,读题不仔细!)

大致思路:

1.先要定义一个结构体,为其创建一个链表。

2.然后是要写两个函数:1个是用来表示总猴砸数的改变,一个是用来表示报数猴砸的。

3.主函数就是读入数据,然后进入函数操作。

下面是代码:

#include
using namespace std;
int n,m;
struct node{                   		 //首先定义一个结构体
int n;
node *next,*ahead;        	 //使用两个指针为结点分配其位置
};
node*ahead;node*tail;
void create(node* &head,int &n){		 //第一个函数是用来表示所剩总猴子数的
node* tail=head;
for(int i=1;i<=n;i++){			 //开始从第一个循环
node* unit=new node;		 //定义一个新的结点
unit->n=i;					 //移动结点
tail->next=unit;
tail=unit;
}
head=head->next;			//每次都要移动开始的那一个
tail->next=new node;		//因为开始的移动了,所以结尾的下一个也要移动到新的第一个去,形成一个环
node* unit=head;
for(int i=1;i<=n;i++){
unit->next->ahead=unit;		//相当与插入一个结点
unit=unit->next;	//移动这个结点
}
tail->next=head;		 //tips:技巧处理:将收尾连接,形成一个环
head->ahead=tail;
}
void s(node* &head,int &m){		//第二个函数是用来表示报数的猴子的
int x=n-1;int k=0;
node* unit=head;
while(x){
k++;
if(k==m){
unit->ahead->next=unit->next;//这里是删除一个结点的意思
unit->next->ahead=unit->ahead;
k=0;
x--;
}
unit=unit->next;
}
cout<n<>n>>m;				//输入猴子数n和所数到的那个数将会被退出圈子的数m
while(n!=0||m!=0){		//满足条件就执行上面的函数
node*head=new node;
create(head,n);
s(head,m);
cin>>n>>m;
}
return 0;
}


 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c++ 链表 c语言 编程