洛谷 P1160 队列安排【Python】

本文分享了一道洛谷刷题题目的解决过程,从最初使用Python列表导致超时,到尝试链表实现仍遇到瓶颈,最终采用双向链表优化方案成功AC。文章详细记录了作者的心路历程和技术心得。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接
浅浅地记录我自己的洛谷刷题情况
这一题做的可真是花费了我九六二虎之力,因为python容易超时,不管我自己怎么苦思冥想,都总是不能AC,后面终于找到用Python做的方法了,也学到了许多


目录

一、问题重述

1.题目描述

2.输入格式

3.输出格式

4.输入输出样例

5.说明/提示

二、大概思路

三、完整AC代码

四、收获与心得


问题重述

题目描述

输入格式

输出格式

输入输出样例

#样例1
输入:
4
1 0
2 1
1 0
2
3
3
输出:
2 4 1

说明/提示


大概思路

  1. 看到这第题第一眼,我轻蔑的看一眼,就这?不就一个列表搞定嘛,所以我果断敲出了下面的代码
N = int(input())
queue = [1]
def put(people, k, p):
    # people:入队的人
    # k:要在几号同学旁边入队
    # p:在他的左边还是右边
    idx = queue.index(k)        # 找到k的下标
    if p == 0:                  # 如果要在k同学的左边入队
        queue.insert(idx, people)
    else:
        queue.insert(idx + 1, people)

def out(s):
    for i in s:
        queue.remove(i)

for people in range(2, N + 1):
    k, p = map(int, input().split())
    put(people, k, p)

M = int(input())
s = set()
for i in range(M):
    s.add(int(input()))
out(s)
n = len(queue)
for i in range(n):
    if i != n - 1:
        print(queue[i], end=" ")
    else:
        print(queue[i])

然而我小看了普及难度的题目,他果断给我抛出了

后面我看了以下数据大小,100000这说大不大说小不小的数字,让进行插入和删除操作的时候,因为列表是在内存空间里面一段连续的区域,每次插入删除都要移动后面的数据,100000这么多次反复操作,时间损耗可想而知

2.于是我查了以下,发现这题应该用链表实现,因为链表的插入和删除不用移动后面的数据,这样他的时间复杂度应该是可以大大缩小的,然而,当我满是自信的交出下面的代码时

class Node:
    def __init__(self, item):
        self.item = item
        self.next = None
        self.pre = None

class LinkList:
    def __init__(self, head=None):
        self.head = head

    def append(self):
        node = Node(1)
        self.head = node

    def insert(self, number, k, p):
        node = Node(number)
        cur = self.head
        while cur:
            if cur.item == k:           # 找到要插入的位置
                if p == 0:              # 如果要站在他的左边
                    if not cur.pre:
                        self.head = node
                        node.next = cur
                        cur.pre = node
                        return
                    else:
                        cur.pre.next = node
                        node.pre = cur.pre
                        node.next = cur
                        cur.pre = node
                        return
                else:
                    node.next = cur.next
                    cur.next.pre = node
                    cur.next = node
                    node.pre = cur
                    return
            cur = cur.next


    def pop(self, lst):
        count = 0           # 已经删除的元素的个数
        while count < len(lst):
            cur = self.head
            while cur:
                if cur.item in lst:
                    if not cur.pre:
                        self.head = cur.next
                        cur.next.pre = None
                    elif not cur.next:
                        cur.pre.next = None
                    else:
                        cur.pre.next = cur.next
                        cur.next.pre = cur.pre
                    count += 1
                cur = cur.next

    def print_llst(self):
        cur = self.head
        while cur:
            if cur.next:
                print(cur.item, end=" ")
            else:
                print(cur.item)
            cur = cur.next


L = LinkList()
L.append()
N = int(input())
for number in range(2, N + 1):
    k, p = map(int, input().split())
    L.insert(number, k, p)
M = int(input())
del_s = set()
for i in range(M):
    del_s.add(int(input()))
L.pop(del_s)
L.print_llst()

OJ给了我狠狠的一把掌,让我无限接近与崩溃边缘

这让我百思不得其解,到底是什么问题呢?于是我认真的反思我的这些代码,发现每次插入和删除的时候我都需要遍历整个链表,这使得我的代码执行效率大大降低,终于,让我发现了别人的优秀的代码,我发现他用列表巧妙的处理了这一问题,最终,得出了我的AC代码


完整AC代码

class Node:
    def __init__(self, date, prev, next):
        self.date = date
        self.prev = prev
        self.next = next
        self.flag = True

N = int(input())
a = [None] * (N + 1)
a[0] = Node(0, a[0], a[0])
a[1] = Node(1, a[0], a[0])
a[0].next = a[1]
a[0].prev = a[1]
for i in range(2, N + 1):
    k, p = map(int, input().split())
    if p == 0:
        a[i] = Node(i, a[k].prev, a[k])
        a[k].prev.next = a[i]
        a[k].prev = a[i]
    else:
        a[i] = Node(i, a[k], a[k].next)
        a[k].next.prev = a[i]
        a[k].next = a[i]
M = int(input())
for i in range(M):
    x = int(input())
    a[x].flag = False

cur = a[0]
while cur.next != a[0]:
    cur = cur.next
    if cur.flag != False:
        print(cur.date, end=" ")
    # if cur.next == a[0]:  # 可以不要
    #     print()
    

收获与心得

  1. 已知N的大小后,马上创建一个列表,也就是像内存申请一片连续的空间,这样既避免了内存的浪费,也极大的便利了后续的插入和删除的相关操作
  2. 在进行插入和删除时,对应的人的编号就是他在列表中对应的下标,同时用指针来表示他们的站位关系,也用flag来表示同学是否还在队列中,当该同学要出队的时候,只需要将他的flag变为False这样在后续输出的时候我们只需要判断flag即可,避免了删除的时候移动这些后续的数据或则不断的改变他们的指针指向而增加了时间,因为我们只需要在输出的时候跳过flag为False的结点即可
  3. 这里的输出值得一提的是,即使不要最后的print()也一样能通过
<think>好的,用户的问题是如何从零基础开始准备Python相关的蓝桥杯研究生组比赛。用户需要学习路径、准备方法和比赛技巧。首先,我需要整理之前提供的引用内容,看看有没有可用的信息。 引用1提到省奖项的小技巧,建议合理规划时间,还有三个月准备。引用2强调基础算法的重要性,获奖率65%,建议认真对待细节,国赛的备赛经验可能也有参考价值。引用3指出Python的pow函数比快速幂更快,这可能是一个实用技巧。 接下来,我需要构建一个适合零基础用户的学习路径。首先肯定是Python基础,然后是算法和数据结构,接着是真题训练,最后是比赛技巧。每个阶段需要具体的时间安排和学习资源。 考虑到用户是研究生组,题目难度可能更高,所以需要更深入的内容。比如动态规划、图论算法可能需要加强。同时,引用3提到的Python内置函数优势,应该提醒用户多利用这些特性节省时间。 另外,引用2提到蓝桥杯获奖的关键在于基础算法和细节处理,所以练习时要注重代码的正确性和效率。模拟考试和错题本也是重要的策略。 可能还需要建议用户参加线上比赛,比如LeetCode周赛,来提升实战能力。同时,合理分配时间,避免过度疲劳,保持学习节奏。 最后,生成相关问题时要围绕学习路径、资源推荐、算法重点、时间管理等方面展开,帮助用户进一步思考。</think>### 零基础Python蓝桥杯研究生组备赛指南 #### 一、学习路径规划(3-4个月) 1. **基础阶段(1个月)** - **Python语法基础**:掌握变量、循环、条件判断、函数、列表/字典操作(推荐《Python编程从入门到实践》) - **内置函数应用**:熟练使用`sorted()`、`pow()`、`itertools`等高效工具[^3] - **基础算法实现**:线性查找、冒泡排序、简单递归等 2. **强化阶段(1.5个月)** - **数据结构**:栈(单调栈)、队列(优先队列)、堆、并查集 - **核心算法**: - 动态规划(背包问题、最长公共子序列) - 图论(DFS/BFS、最短路径算法) - 数论(质数筛法、快速幂) - 掌握时间复杂度分析方法 3. **真题阶段(1个月)** - 完成近5年真题(官网/蓝桥云课) - 每周2套模拟赛训练 - 建立错题本记录典型错误 #### 二、关键技巧 1. **Python特性利用** - 大数运算直接处理(Python支持无限精度整数) - 排列组合使用`itertools.permutations` - 矩阵运算优先使用`numpy` 2. **常见题型应对策略** - **填空题**:注意输出格式要求(大小写、精度) - **编程题**:优先实现$O(nlogn)$解法 - 特殊题型准备:日期计算、状态压缩DP 3. **效率优化技巧** - 输入加速: ```python import sys input = sys.stdin.read().split() ``` - 记忆化搜索使用`lru_cache` - 预处理常用数据(如质数表) #### 三、资源推荐 1. **在线平台** - 蓝桥云课(官方训练) - (P1001~P1500难度题目) - LeetCode(周赛模拟) 2. **参考书籍** - 《算法竞赛入门经典(第2版)》 - 《挑战程序设计竞赛》 3. **时间管理表样例 | 时间段 | 内容 | 目标 | |--------------|----------------------|--------------------------| | 8:00-9:30 | 算法理论学习 | 掌握2种新算法 | | 14:00-17:00 | 真题训练 | 完成1套模拟赛+错题分析 | | 20:00-21:30 | 专题突破(动态规划) | 攻克背包问题变种 | #### 四、注意事项 1. **代码规范** - 变量命名使用英文全称 - 关键步骤添加注释 - 提前编写工具函数(如快速输入) 2. **比赛策略** - 先完成所有填空题 - 编程题按分值从高到低做 - 留30分钟检查输出格式 3. **心理调节** - 每周安排1天休息 - 组队刷题互相监督 - 定期进行压力测试(连续5小时模拟)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值