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

题目描述

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

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

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

输入

输入n和m值。

输出

输出胜利者的编号。

示例输入

5 3

示例输出

4

提示

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


#include 
#include 

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;inext;
            }
            flag=1;
        }
        else//其他情况下指针移动m次
        {
            for(i=0;inext;
            }
        }
        r->next=p->next;//删除链结
    }
    printf("%d\n",p->data);//打印最后剩下的那个编号
    return 0;
}



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


#include 

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;
}



这个方法是我在下面的这位大哥的博客里看到的...下面是他的链接
http://www.cnblogs.com/EricYang/archive/2009/09/04/1560478.html

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



你可能感兴趣的:(SDUTOJ,链表)