题解 P2058 【海港】

· · 题解

超级详细题解(打了6小时,求点赞啊!!!)

首先来讲讲队列和优先队列(非常详细!!!

然后再对题目进行分析,附上代码。

关于队列

队列其实就是一种数据结构 “栈”无需自己写,递归过程中会自动开系统栈 “队列”需要自己写,一般有两种方式:

  1. 用数组模拟实现队列
  2. 用STL中自带的queue(常数比priority_queue大很多,慎用)

① 数组模拟队列


定义       int que[100],L = 1,R =0;
队列不空    while(L<=R)
新元素入队  que[++R] = i;
取队首元素并出队
int cur = que[L++];

②自带STL queue

定义      queue<int> q;
队列不空     while(!q.empty())
新元素入队   q.push(m);
取队首元素   q.front();
队首元素出队  q.pop();

③结构体队列 //图片转自CSDN

我们可以看出用法还是差不多的,只是将整形换成自己定义的结构体一样。

说人话,就是把int换成结构体!!!

④优先队列

定义:说人话就是用个东西把一群元素排队(默认从大到小,可更改为从小到大)

库: #include<queue>

定义队列:


priority_queue<int(或其他类型)> q

priority_queue<int,vector<int>,greater<int>> q(队列从小到大排序)

基本操作: (其中q为定义的队列)注意它没有队列的q.back()

①q.push(x) x为定义的变量,将x压进队列
②q.top()     返回队列第一个元素
③q.pop()    删除队列第一个元素
④q.size()    返回队内元素数量
⑤q.empty()    判断队列是否空,空则返回1,否则返回0;

那么学会了以后我们来做个测试吧!

输入输出
输入 :10 11 5 78
输出 : 5 10 11 78

总结:优先队列相当与动态的数组(自动帮你排序)所以对于要遍历时时更新元素的情况下,用优先队列会方便很多

既然学了优先队列,那么还是建议大家去水水合并果子

传送门

算法介绍结束!!!

下面来分析题目

首先看到这里,我们首先的思路是开个结构体。

从第一个船开始遍历找到这个船24小时内进港的船,再统计国籍数,输出,进行下一波遍历。

那么问题就来了,我们如果记录每个状态可能会爆内存。(算内存应该都会吧)我们能否对这个算法进行优化呢???

但是细细一想。这群人来的批数有用吗???

我们也许只要开个结构体存人头数(这个人来的时间和这个人的所属国籍)不就行了嘛???

那么问题就很好办了。

我们的思路是:

先读进人数,再读进每个人的国籍,把人到来的时间和国籍放进队列。去重计数(因为对答案没贡献)。

其次,队列并不要记录每个结构体,它只要记住主时间线之前24小时内的结构体即可。

所以我们先全记下来,再判重,之后再进行队列和答案的更新,最后输出答案即可(答案其实不用清零,因为之前的答案有可能会对现在的做贡献,这样就不用每次读入都遍历了)

详细分析


  #include<cstdio>
#include<queue>
#define rei register int
using namespace std;
int n, t, m, x;
int temp_nation[1000005];
int ans;

struct node
{
    int s, t;
    //made in china
};
queue<node>ship;
node h;

int main()
{
    scanf("%d",&n);
    for(rei i=1;i<=n;i++)
    {
        scanf("%d%d",&t,&m);
        while(!ship.empty())//只要还有人就对队列进行检查
        {
            h = ship.front();//循环取队头(由于时间是单调递增的)
            if(h.t+86400<=t)//如果在时间外(不符合条件),则对答案和队列进行更新(删减)
            {
                temp_nation[h.s]--;//这个国籍人数总数减1(因为这不是24小时内的人)
                if(temp_nation[h.s]==0)   ans--;//如果这个国籍没有人了,则答案数减1(之前记过)
                ship.pop();//把这个被时代所淘汰的人给丢掉
                continue;//因为是单调递增的,所以有可能还会有,继续去找
            }
            break;//如果现在这个在24小时内,后面的肯定也符合条件,直接退出
        }
        for(rei j=1;j<=m;++j) //查完前面后,我们就对这只本身的船进行统计
        {
            scanf("%d",&x);//输入国籍
            h.s = x, h.t = t;//存进结构体
            ship.push(h);//把这个人(结构体)给存进队列
            temp_nation[x]++;//这个国籍的人加1(桶排思想)
            if(temp_nation[x]==1)  ans++;//如果这个国籍是!相对!第一次出现,那么就算上他
        }
        printf("%d\n",ans);//模拟完了以后就输出答案
    }
    return 0;
}

是不是贼详细???求点赞,求管理员过!!

说实话像我这么良心的博主真的很少见了!