ccf 201712-2 游戏


思路

需要解决两个问题:

  • 如何实现将被淘汰的人从人群中删去,即此人不再参与报号
  • 如何实现循环,即到达最后一个人之后,下次返回第一个人

数组

  • 数组的每一个单元是不能删除的,只能通过做标记来表示这个位置的人被淘汰(如值等于-1表示这个位置的人被淘汰),但是这个空间并没有消失,每次遍历都还要遍历一下这些已经被淘汰的人的位置
  • 比如说,有1000个人,淘汰到最后只剩下了2个人在相互报数,但是开辟的数组大小是1000,2人人报数时仍需要遍历这1000个数组空间,尽管数组中其他位置的人已经被淘汰了,这样会导致超时
  • 我们希望能将这些淘汰的位置彻底删除,而不是继续留在结构中,每次都要访问

链表 list

  • 数组的单元是没法删除的,但是链表的结点是可以删除的,因此对于淘汰的人,不是将其值赋值为-1,而是将其结点删除
  • 链表 list 的相关操作:
#include<list>  //头文件

list<int> l;  //构建一个空链表
for(int i = 1; i <= n; ++i)  //依次从尾部插入n个结点,值分别为1、2、3……
	l.push_back(i);

list<int>::iterator it = l.begin();   //链表的迭代器

//删除it指向结点,并
list<int>::iterator temp = it;  
it++;
l.erase(temp); 

//it超出了范围,返回第一个
if(it == l.end())
	it = l.begin();

cout << *it << endl;  //输出迭代器对应的元素值
  • 注意begin()是第一个数据结点,end()是最后一个数据结点之后的结点(无数据),如果 it 等于end(),则说明已跑到了最后一个人的后面,需要返回第一个人
  • 代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<list>
using namespace std;

int main()
{
    int n, k;
    list<int> l;
    cin >> n >> k;
    for(int i = 1; i <= n; ++i)
        l.push_back(i);
    list<int>::iterator it = l.begin();  
    int num = 0;
    while(l.size() > 1)
    {
        num++;
        if(num % k == 0 || num % 10 == k)
        {
            list<int>::iterator temp = it;
            it++;
            l.erase(temp); 
        }
        else
            it++;

        if(it == l.end())
            it = l.begin();
    }
    cout << *it << endl;

    return 0;
}

队列 queue

  • 队列是一段入,另一端出
  • 报数的思路是:队首到队尾依次是1、2、3……n,每次报数的同时出队,如果没有被淘汰,则重新入队(到队尾),如果被淘汰了,那就不用管了
  • 队列 queue 的相关操作:
#include<queue>  //头文件

queue<int> q;  //构建一个空队列

//插入元素,队首到队尾依次是1、2、3……n
for(int i = 1; i <= n; ++i)
	q.push(i);  

int a = q.front();  //获取队首元素值
q.pop();  //队首出队
q.push(a);  //入队
  • 代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int main()
{
     int n, k;
    queue<int> q;
    cin >> n >> k;
    for(int i = 1; i <= n; ++i)
        q.push(i);
    int num = 0;
    while(q.size() > 1)
    {
        num++;
        if(num % k == 0 || num % 10 == k)
        {
            q.pop(); 
        }
        else
        {
            int a = q.front();
            q.pop();
            q.push(a);
        }
    }
    cout << q.front() << endl;

    return 0;
}

对比

  • 数组的思想是比较好想的,但是任意超时
  • 链表的思想和数组方式很相近,但是链表里面涉及迭代器,不是很好操作
  • 队列代码和思路比较简单,但是里面出队入队的思路不任意通过题目题意想到,题目题意想到的一般是数组或者链表的做法
  • 分别用链表和队列交了两次,下面是 list,上面是 queue,发现队列的速度更快,可能是由于 list 的删除操作的复杂度不是O(1),导致慢一点
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值