洛谷P1160 队列安排

该博客详细解释了如何解决洛谷P1160问题,即根据特定规则安排班级队列并处理出队情况。博主通过使用L和R数组模拟队列状态,分别记录每个同学左侧和右侧同学的编号,并讨论了不同入队情况的处理。同时,提出了利用flag数组标记出队同学,避免在输出时包含已出队同学的策略。

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

题目大意:

一个学校里老师要将班上 N N N 个同学排成一列,同学被编号为 1 ∼ N 1∼N 1N,他采取如下的方法:

1、先将 1 1 1 号同学安排进队列,这时队列中只有他一个人;

2、 2 − N 2−N 2N 号同学依次入列,编号为 i i i 的同学入列方式为:老师指定编号为 i i i 的同学站在编号为 1 ∼ ( i − 1 ) 1∼(i−1) 1(i1) 中某位同学(即之前已经入列的同学)的左边或右边;

3、从队列中去掉 M ( M < N ) M(M<N) M(M<N) 个同学,其他同学位置顺序不变。

在所有同学按照上述方法队列排列完毕后,老师想知道从左到右所有同学的编号

说明/提示:

数据范围:

对于 20 20 20% 的数据,有 1 ≤ N ≤ 10 1≤N≤10 1N10

对于 40 40 40% 的数据,有 1 ≤ N ≤ 1000 1≤N≤1000 1N1000

对于 100 100 100% 的数据,有 1 ≤ N , M ≤ 100000 1≤N,M≤100000 1N,M100000

思路/分析:

既然每次新同学入列都是在某个已入列同学的左侧或右侧 那么自然想到用两个数组。
L [ M A X ] L[MAX] L[MAX] R [ M A X ] R[MAX] R[MAX] 来保存队列信息。
L [ i ] 、 R [ i ] L[i]、R[i] L[i]R[i] 分别记录第i个同学左侧同学和右侧同学的编号。(初始化为 0 0 0 )
这样只要知道 K K K (即同学的编号)和 P P P 的值( 0 0 0 左侧 1 1 1 右侧)就可以直接模拟入队操作。
仔细思考就知道 入队要分两种情况 这里以 p = 0 p=0 p=0 即插入k号同学左侧为例来说明。
(1) k k k 号同学左侧没有同学 即 L [ k ] = 0 L[k]=0 L[k]=0 时:
执行下列操作即可( i i i 为当前入队的同学编号)

L[k]=i;
R[i]=k

(2) k k k 号同学左侧有同学 即 L [ k ] ! = 0 L[k]!=0 L[k]!=0 时:
先记录i同学的左右同学编号。(因为后面要修改其左右同学的信息)
然后修改k号同学左侧同学的信息 即 $R[L[k]]=i
最后修改k号同学的信息 即 L [ k ] = i L[k]=i L[k]=i

L[i]=L[k];
R[i]=k;
R[L[k]]=i;
L[k]=i;

到此 我们的入队模拟已经完成了!
那么考虑输出的情。既然是从向右输出编号 那么我们需要最左侧同学的编号。
当然可以循环遍历 L [ n ] L[n] L[n] 数组 L [ i ] = 0 L[i]=0 L[i]=0 时的i即是最左侧同学
这里提供另外一种方法 在执行入队操作的时候 我们用 l e f t left left 标记最左侧同学的编号。
p = 0 p=0 p=0 且入队操作已经模拟完成时 我们判断L[i]是否为 0 0 0 若为 0 0 0 l e f t = i left=i left=i 否则不做操作。
好了 现在队列的头也有了 终于可以进行输出了!
但是题目还有出队的操作啊 其实没有必要进行出队的模拟了。
我们使用一个 f l a g flag flag 数组 初始化为 0 0 0 读入出队的同学编号 i i i 然后 f l a g [ i ] = 1 flag[i]=1 flag[i]=1
最后遍历队列的时候 若 f l a g [ i ] = 1 flag[i]=1 flag[i]=1则不进行输出即可。

代码:

#include <bits/stdc++.h>
using namespace std;
int L[100005],R[100005],flag[100005];
int main(){
    int n,m,left = 1;
    cin >> n;
    L[1] = 0,R[1] = 0;
    for(int i = 2;i <= n;i++){
        int temp1,temp2;
        cin >> temp1 >> temp2;
        if(temp2 == 0){
            if(L[temp1] == 0){
                L[temp1] = i;
                R[i] = temp1;
            }else{
                L[i] = L[temp1];
                R[i] = temp1;
                R[L[temp1]] = i;
                L[temp1] = i;
            }
            if(L[i] == 0){
            	left = i;
			}
        }else{
            if(R[temp1] == 0){
                R[temp1] = i;
                L[i] = temp1;
            }else{
                L[i] = temp1;
                R[i] = R[temp1];
                L[R[temp1]] = i;
                R[temp1] = i;
            }
        }
    }
    cin >> m;
    for(int i = 0;i < m;i++){
        int temp1;
        cin >> temp1;
        flag[temp1] = 1;
    }
    while(left != 0){
        if(!flag[left]){
			cout << left << ' ';
		} 
        left = R[left];
    }
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值