洛谷 P2058 海港(queue优化)

文章介绍了P2058编程题的背景和要求,即统计每艘船到达后24小时内乘客来自的国家数。给出了两种解题思路,一种是利用桶排序的空间换时间策略,另一种是利用队列处理时间条件,确保效率。文章强调了数据结构如队列在解决此类问题中的关键作用。
摘要由CSDN通过智能技术生成

P2058 [NOIP2016 普及组] 海港 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

题目描述

小 K 是一个海港的海关工作人员,每天都有许多船只到达海港,船上通常有很多来自不同国家的乘客。

小 K 对这些到达海港的船只非常感兴趣,他按照时间记录下了到达海港的每一艘船只情况;对于第 i 艘到达的船,他记录了这艘船到达的时间 ti (单位:秒),船上的乘客数 ki,以及每名乘客的国籍 xi,1,xi,2,…,xi,k

小K统计了 n 艘船的信息,希望你帮忙计算出以每一艘船到达时间为止的 24 小时(24 小时 =86400 秒)内所有乘船到达的乘客来自多少个不同的国家。

形式化地讲,你需要计算 n 条信息。对于输出的第 i 条信息,你需要统计满足 ti−86400<tpti 的船只 p,在所有的 xp , j 中,总共有多少个不同的数。

输入格式

第一行输入一个正整数 n,表示小 K 统计了 n 艘船的信息。

接下来 n 行,每行描述一艘船的信息:前两个整数 tiki 分别表示这艘船到达海港的时间和船上的乘客数量,接下来 ki 个整数xi , j 表示船上乘客的国籍。

保证输入的 ti 是递增的,单位是秒;表示从小K第一次上班开始计时,这艘船在第 ti 秒到达海港。

输出格式

输出 n 行,第 i 行输出一个整数表示第 i 艘船到达后的统计信息。

输入:

3
1 4 4 1 2 2
2 2 2 3
10 1 3

输出:

3
4
4

思路:

统计每一艘船到达时,前24小时内的国家总数,最简单的方法就是输入的时候就进行判断,用类似于桶排序的方法存放每个国家的人数,这样损失空间换取时间,一旦有新的国家的人到达判断一手就行。


40昏:

#include<bits/stdc++.h> 
using namespace std;
int n;
int cou[100005];
//hash表 桶 (?) 
int main()
{
    cin>>n;
    long long cnt=0;
    while(n--){
        long long t,k,x;
        cin>>t>>k;
        //时间没有考虑  
        while(k--){
            cin>>x;
            if(cou[x]==0) cnt++;
            cou[x]++;
        }
        cout<<cnt<<endl;
    }
    return 0;
}

有40分的原因就是有些数据的时间差并没有超过86400s,也就是说,我们没有考虑时间。


100昏:

想要AC就需要借助数据结构 队列 queue 。上述的代码的思路延用,只是需要再多考虑一个时间的问题。以新到达的船的时间为起点,向左搜索到<t-86400的那一艘船,并且只统计属于该时间段内的船。但是,这样的需要的时间非常大,t有1e9级。我们注意到:“保证输入的 ti 是递增的”说明我们在剔除不属于该时间段的船的时候,是按照输入时候的顺序踢出的,也就是:先进先出

队列中存放每一个人的信息,如果队首的人的时间t已经不再属于我们需要统计的时间段内就pop,当然pop之前需要对这个人的国家数进行删除。

#include<bits/stdc++.h> 
using namespace std;
int n;
int cou[100005];//存放所有国家de人数 类似于 桶  
struct Person{
    int country;
    int t;
}; 
queue<Person> q;//存放在时间段内的所有人 
int main()
{
    cin>>n;
    int ans=0;
    for(int i=1;i<=n;i++){
        int t,k;
        cin>>t>>k;
        while(!q.empty()){
            //栈也好 队列也好 在查询元素、弹出元素前都要先判断empty
            Person temp=q.front();
            if(temp.t+86400<=t){
                //队列顶部的那一个人不再时间范围内 
                //踢出队列 
                cou[temp.country]--;
                if(cou[temp.country]==0) ans--;
                //说明有一个国家的人数已经减到0了,总数--
                q.pop(); 
            }
            else break;
        }
        //存放新的数据 并进行输出 
        int x;
        for(int j=1;j<=k;j++){
            cin>>x;
            Person temp;
            temp.t=t;temp.country=x;
            q.push(temp);
            cou[x]++;
            if(cou[x]==1) ans++;
        }
        cout<<ans<<endl;
    }
    return 0;
}

总结:使用栈或者是队列等数据结构最重要的是想出数据的进出方式,以及容器到底存放什么数据!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
洛谷p1238是一个题目,具体要求是给定一个迷宫,求从起点到终点的最短路径。这个问题可以使用链表来表示迷宫,并使用广度优先搜索算法来求解最短路径。 以下是一个示例代码,演示了如何使用链表和广度优先搜索算法来解决洛谷p1238题目中的迷宫问题: ```python from collections import deque # 定义迷宫的链表节点类 class Node: def __init__(self, x, y, val): self.x = x self.y = y self.val = val self.next = None # 构建迷宫的链表 def build_maze(maze): m = len(maze) n = len(maze[0]) head = Node(0, 0, maze[0][0]) curr = head for i in range(m): for j in range(n): if i == 0 and j == 0: continue node = Node(i, j, maze[i][j]) curr.next = node curr = node return head # 广度优先搜索算法求解最短路径 def bfs(maze): m = len(maze) n = len(maze[0]) visited = [[False] * n for _ in range(m)] queue = deque([(0, 0, 0)]) # (x, y, step) visited[0][0] = True while queue: x, y, step = queue.popleft() if x == m - 1 and y == n - 1: return step for dx, dy in [(1, 0), (-1, 0), (0, 1), (0, -1)]: nx, ny = x + dx, y + dy if 0 <= nx < m and 0 <= ny < n and not visited[nx][ny] and maze[nx][ny] == 0: queue.append((nx, ny, step + 1)) visited[nx][ny] = True return -1 # 示例迷宫 maze = [ [0, 1, 0, 0, 0], [0, 1, 0, 1, 0], [0, 0, 0, 0, 0], [0, 1, 1, 1, 0], [0, 0, 0, 1, 0] ] # 构建迷宫的链表 maze_head = build_maze(maze) # 使用广度优先搜索算法求解最短路径 shortest_path = bfs(maze) print("最短路径长度为:", shortest_path) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Awars_zpp

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值