猴子大王【链表】

1.猴子大王

有 n 只猴子围成一圈,编号为 1~n,打算从中选出一个大王。经过协商,决定选大王的规则如下:从第一只猴子开始循环报数,数到 k 的猴子出圈,然后从下一只猴子继续报数出圈……最后剩下来的那只猴子就是大王。

inputs

一行两个正整数 n 和 k,之间用一个空格分开,2≤n≤1000,2≤k≤10^9 。

6 4

outputs

一行 n 个正整数,表示 n 只猴子依次出圈的编号,中间用一个空格隔开

4 2 1 3 6 5

代码思路

1.由于到末尾需要从头开始,所以将数据存入成环的链表中
2.数数直到k,记录此时的p以及它的前一个结点pre,将p剔除环,并释放内存

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
typedef struct node
{
    
    
    int data;
    struct node *next;
} Node;

int main()
{
    
    
    Node *Head,*p,*pre,*pTail;
    int n,i,n2,j,k;
    while(cin>>n>>k)
    {
    
    
        i=1;
        n2=n;
        
        Head=(Node*)malloc(sizeof(Node));
        Head->data=i++;
        n--;//给Head赋值一次总数-1
        pTail=Head;//将2-n个数存入链表
        while(n--)
        {
    
    
            p=(Node *)malloc(sizeof(Node));
            p->data=i++;
            pTail->next=p;
            pTail=p;
        }
        pTail->next=Head;
        p=Head;


        while(n2>0)
        {
    
    
            for(j=1;j!=k;j++)//记录p、pre
            {
    
    
                pre=p;
                p=p->next;
            }
            (n2==1)?printf("%d\n",p->data):printf("%d ",p->data);
            n2--;
            pre->next=p->next;//剔除结点p
            free(p);
            p=pre->next;
        }

    }
    return 0;
}

2.猴子大王(进阶)

将 N 个人排成一排,编号 1~N。从第 1 人开始进行 1~M 正向报数,报到 M 的人出列,再从下一个人开始继续1~M 报数、出列。(注意:按某个方向报数报到尾部时,再反方向继续报数)。如此进行下去,直到剩下一人为止,输出最后一个人的编号。

inputs

一行两个正整数 N 和 M,2≤N,M≤300,M≤N,两个数之间用一个空格分隔。

9 3

outputs

一行一个正整数,表示小明在队列中的编号。

8

代码思路

(1)由于需要正向、反向查数,所以需要双向链表,d=1/d=2控制正向、反向
(2)删除结点时,如果删除了头节点,需要重新设置头节点 Head=p->next; 如果删除了尾结点,需要重新设置尾节点 pTail=p->pre; 直至剩下头尾两个结点。
(3)当知剩下头尾两个结点时,根据p的指向和d的值会产生4种情况,删除一个后,Head->data为答案。

注意:双向链表中每个节点都需要考虑当前p的前一个pre的指向、后一个next的指向

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
typedef struct node
{
    
    
    int data;
    struct node *next;
    struct node *pre;
} Node;

int main()
{
    
    
    Node *Head,*p,*q,*pTail;
    int n,k,i,d,num;
    cin>>n>>k;

    //创建双向链表
    i=1;
    Head=(Node*)malloc(sizeof(Node));
    Head->data=i++;
    Head->pre=NULL;
    Head->next=NULL;
    n--;
    q=Head;
    while(n--)
    {
    
    
        p=(Node *)malloc(sizeof(Node));
        p->pre=NULL;
        p->next=NULL;
        p->data=i++;
        q->next=p;
        p->pre=q;
        q=p;
    }

    
    pTail=q;//设置尾结点
    p=Head;
    d=1;
    num=0;
    while(Head!=pTail)//直到剩下头尾两个节点
    {
    
    
        num++;
        if(num==k)
        {
    
    
            num=0;
            if(p==pTail)//删尾,改变尾结点的位置
            {
    
    
                pTail=p->pre;
                p=pTail;
                d=2;
                continue;
            }
            if(p==Head)//该删头,改变头结点的位置
            {
    
    
                Head=p->next;
                p=Head;
                d=1;
                continue;
            }
            p->pre->next=p->next;//删除其他节点
            p->next->pre=p->pre;
            if(d==1)
                p=p->next;
            else p=p->pre;
            continue;
        }


        if(d==1)//只剩下头尾两个节点时
        {
    
    
            if(p==pTail)
            {
    
    
                p=p->pre;
                d=2;
            }
            else
                p=p->next;

        }
        else
        {
    
    
            if(p==Head)
            {
    
    
                p=p->next;
                d=1;
            }
            else
                p=p->pre;
        }

    }
    printf("%d\n",Head->data);


    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_46126258/article/details/108587433