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

题目描述

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

后来想了想,这个用循环队列也能实现,比链表简单多了,就是一个下标的运算,类似于那个数学解法,不过这也是一种方法,代码没写,自己去思考吧...



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值