P1160 队列安排 c语言

题目描述

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

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

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

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

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

输入格式

第 11 行为一个正整数 NN,表示了有 NN 个同学。

第 2\sim N2∼N行,第 ii 行包含两个整数 k,pk,p,其中 kk 为小于 ii 的正整数,pp 为 00 或者 11。若 pp 为00,则表示将 ii 号同学插入到 kk 号同学的左边,pp 为 11 则表示插入到右边。

第 N+1N+1 行为一个正整数 MM,表示去掉的同学数目。

接下来 MM 行,每行一个正整数 xx,表示将 xx 号同学从队列中移去,如果 xx 号同学已经不在队列中则忽略这一条指令。

输出格式

11 行,包含最多 NN 个空格隔开的正整数,表示了队列从左到右所有同学的编号,行末换行且无空格。

输入输出样例

输入 #1复制

4
1 0
2 1
1 0
2
3
3

输出 #1复制

2 4 1

说明/提示

样例解释:

将同学 22 插入至同学 11 左边,此时队列为:

2 1

将同学 33 插入至同学 22 右边,此时队列为:

2 3 1

将同学 44 插入至同学 11 左边,此时队列为:

2 3 4 1

将同学 33 从队列中移出,此时队列为:

2 4 1

同学 33 已经不在队列中,忽略最后一条指令

最终队列:

2 4 1

数据范围

对于 20\%20% 的数据,有 1\leq N\leq 101≤N≤10;

对于 40\%40% 的数据,有 1\leq N\leq 10001≤N≤1000;

对于 100\%100% 的数据,有 1\leq N,M\leq1000001≤N,M≤100000。

解法一:用数组模拟双向链表

#include<iostream>
#include<cstdio>
using namespace std;
 
int L[100005],R[100005],flag[100005];//L[i]表示i号同学左侧同学的编号
 
int main()
{
    int n,m,left=1;
    scanf("%d",&n);
    L[1]=0,R[1]=0;
    for(int i=2;i<=n;i++)
    {
        int temp1,temp2;
        scanf("%d %d",&temp1,&temp2);
        if(temp2==0)    //i插到temp1左侧
        {
            if(L[temp1]==0) //temp1 左侧没有人
            {
                L[temp1]=i;//temp1 左侧的人是 i
                R[i]=temp1;//i 右侧的人是 temp1
            }
            else//temp1 左侧有人
            {
                L[i]=L[temp1];//i 左侧的人是temp1 左侧的人
                R[i]=temp1;//i 右侧的人是 temp1
                R[L[temp1]]=i;//temp1 原来左侧的人的现在右侧的人是 i
                L[temp1]=i;//temp1 的左侧的人是 i
            }
            if(L[i]==0) //i左侧没有人
                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;
            }
        }
    }
    scanf("%d",&m);
    for(int i=0;i<m;i++)
    {
        int temp1;
        scanf("%d",&temp1);
        flag[temp1]=1;//给出队的同学打上标记
    }
    while(left!=0)  //打印编号
    {
        if(!flag[left])
            printf("%d ",left);
        left=R[left];
    }
    return 0;
}

解法二:用数组模拟双向链表 

#include<stdio.h>
int n,m;
struct node{
	int l,r;
	int id;
}a[1000005];
int main(){
	scanf("%d",&n);
	for(int i=2;i<=n;i++){//从2开始,将i号学生插到k号的一边 
		int k,p;
		scanf("%d%d",&k,&p);//第几个人的哪一边 
		if(p==1){//插在右边 
			//这四行是在将a[k],a[k].r,a[i]之间两两建立双向联系 
			a[i].r=a[k].r;//i右边的人是原来k右边的人 
			a[i].l=k;//i左边的人是k 
			a[a[k].r].l=i;//原来k右边的人现在左边的人是i 
			a[k].r=i;//k右边的人是i 
		}
		else{//插在左边,l,r对调即可 
			a[i].l=a[k].l;
			a[i].r=k;
			a[a[k].l].r=i;
			a[k].l=i;
		}
	}
	scanf("%d",&m);
	for(int i=1;i<=m;i++){
		int x;
		scanf("%d",&x);
		a[x].id=1;//标记要删除的人 
	}
	int now;
	for(int i=1;i<=n;i++) if(a[i].l==0&&a[i].id!=1) now=i;//如果没有赋值自动赋为0 
	//找到整个队列的第一个人 
	//如果左边没人且这个人不会被删,将其赋给now 
	while(now){//如果now存在的话 
		if(a[now].id==0) printf("%d ",now);
		now=a[now].r;//下一个 
	}
	return 0;
}

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值