排队



题目:


分析:

这道题目用链表来模拟整个过程,就只需要指针的移动和链表节点的删除两种操作就好了。首先新建一个足够长的链表表示长队,链表节点存的数据就是每个人的编号。然后用一个变量m来记录当前接受服务的人的编号,以后每数m次,就把该节点删除,因为不能接受服务的人直接离开,所以可以直接删除该节点。现在我们来讨论一下初始链表的长度。由于答案输出的最大编号不超过10000,所以链表的长度也不会超过10000。那么是不是链表的初始长度就为10000呢?答案是否定的。我们可以发现,第一个接受服务的人是2号,那么,也就是意味着在2号后面的所有偶数号码全部都要离开,而我们又可以确定2号是第一个被删除的,可以不用考虑,一起忽略,所以我们直接建一个全部存放奇数的链表,第一个节点的编号是3号,这样就能省掉一半的节点。注意到如果这样的话,那么我们应该要输出的是第n-1个接受服务的人的编号,因为2号就是第一个接受服务的人。另外,由于n最小为1,而二号又被我们忽略,所以要加一个判断,当n为1时,输出为2。然后通过实验,又可以发现,当n=1000时,输出结果为9863,那么也就是说最大编号为9863,这样又可以省下一些节点。


代码:

#include<iostream>
#include<stdlib.h>
using namespace std;

struct Node
{
    int num;
    Node *next;
};

int main()
{
    Node *head, *p, *newp, *p1;
    int i, j, n, m;

    cin >> n;
    head = (Node*)malloc(sizeof(Node));
    head->next = NULL;
    p = head;

    for (i = 3; i<9864; )                //最大编号为9863
    {
        newp = (Node*)malloc(sizeof(Node));
        newp->num = i ;                     
        p->next = newp;                  
        newp->next = NULL;
        p = p->next;                   
        i = i + 2;                     //偶数编号可以不考虑
    }

    for (i = 2; i<n; i++)
    {
        m = head->next->num;                   //记录当前接受服务的号数
        p = head;
        p1 = p->next;                               
        p->next = p1->next;                   //删除当前接受服务的人
        delete p1;
        p = head;
        while (p->next != NULL)
        {
            for (j = 0; j < m - 1; j++)        //往后数m次
            {
                if (p->next == NULL)
                    break;
                p = p->next;
            }
            if (p->next == NULL)
                break;
            p1 = p->next;
            if (p1->next == NULL)
                break;
            p->next = p1->next;              //删除第m个节点
            delete p1;
        }
    }
    if(n==1)
        cout<<"2"<<endl;                    //n=1的情况
    else
        cout << head->next->num << endl;
    return 0;
}


原文地址:https://www.cnblogs.com/jiuweilinghu/p/5943250.html