您的位置:首页 > 其它

SDUTOJ 1197 约瑟夫问题——循环链表解法数学解法和循环队列

2014-03-29 00:52 477 查看

题目描述

n个人想玩残酷的死亡游戏,游戏规则如下:

n个人进行编号,分别从1到n,排成一个圈,顺时针从1开始数到m,数到m的人被杀,剩下的人继续游戏,活到最后的一个人是胜利者。

请输出最后一个人的编号。

输入

输入n和m值。

输出

输出胜利者的编号。

示例输入

5 3


示例输出

4


提示

第一轮:3被杀第二轮:1被杀第三轮:5被杀第四轮:2被杀

#include <stdio.h>
#include <stdlib.h>

struct node
{
int data;
struct node *next;
};

int main()
{
int n,m,flag=0,i;
struct node *head,*p,*q,*r;
p=(struct node *)malloc(sizeof(struct node));//游动指针
p->next=NULL;
r=(struct node *)malloc(sizeof(struct node));//标记指针
r->next=NULL;
head=(struct node *)malloc(sizeof(struct node));//头指针
head->data=1;//头必定为1
head->next=NULL;
p=head;//游动指针一开始指向头
scanf("%d%d",&n,&m);
for(i=2;i<=n;i++)
{
q=(struct node *)malloc(sizeof(struct node));//开链节
q->data=i;//为每个链结赋值
p->next=q;
q->next=NULL;
p=q;//游动指针向后移动
}
p->next=head;//连接成环
p=head;//游动指针开始遍历
while(p->next!=p)//设置跳出条件,如果一个链结的尾指针存的是这个链结的头的话,那么就说明就剩下一个链结了,此时跳出循环
{
if(flag==0)//如果画图可以发现,第一次实际上指针只移动了(m-1)次
{
for(i=0;i<m-1;i++)
{
r=p;//标记p的上一个链结
p=p->next;
}
flag=1;
}
else//其他情况下指针移动m次
{
for(i=0;i<m;i++)
{
r=p;//标记p的上一个链结
p=p->next;
}
}
r->next=p->next;//删除链结
}
printf("%d\n",p->data);//打印最后剩下的那个编号
return 0;
}


其实还有更简单的方法:(数学方法)

<span style="font-size:24px;">#include <stdio.h>

int main()
{
int n, m, i, s = 0;
scanf("%d%d", &n, &m);
for (i = 2; i <= n; i++)
{
s = (s + m) % i;
}
printf ("%d\n", s+1);
return 0;
}</span>


这个方法是我在下面的这位大哥的博客里看到的...下面是他的链接
http://www.cnblogs.com/EricYang/archive/2009/09/04/1560478.html
后来想了想,这个用循环队列也能实现,比链表简单多了,就是一个下标的运算,类似于那个数学解法,不过这也是一种方法,代码没写,自己去思考吧...
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: