P1160 队列安排

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

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

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

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

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

输入格式
第1行为一个正整数N,表示了有N个同学。

第2−N行,第i行包含两个整数k,p,其中k为小于i的正整数,p为0或者1。若p为0,则表示将i号同学插入到kk号同学的左边,p为1则表示插入到右边。

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

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

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

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

说明/提示
样例解释:

将同学2插入至同学1左边,此时队列为:

2 1

将同学3插入至同学2右边,此时队列为:

2 3 1

将同学4插入至同学1左边,此时队列为:

2 3 4 1

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

2 4 1

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

最终队列:

2 4 1

数据范围

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

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

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

解题思路:
虽然表面看起来像是一道队列的题,但是仔细想想你就会发现,用队列并不是很好做,他每次删除一个元素的时候都会使他前后的元素位置发生改变。这时候你就会发现,用链表就显得很合适。因为他是一串操作,并且每次操作都是把相应位置的元素移走,然后再把前面的元素和后面的元素连接起来。并且,他每个元素只出现一次,因此用双向链表就会很好的达到我们的目的。
有的同学可能会说链表我并不熟悉,不是很会使用只是数据结构接触过(比如我),不过你用一个结构体数组还是很好实现的,因为这真的只是一道水题。
AC代码:

#include<iostream>
#include<bits/stdc++.h>
#include<algorithm>
#include<math.h>
#include<string.h>
#include<string>
using namespace std;
const int N = 1e6+10;
struct line
{
	int pr, ne;
	bool mk;
}a[N]; 
int f[N];
int n , m;
int ans = 0;
int main()
{
	cin >> n;
	int i , j;
	int k , p;
	a[0].ne = 1;
	a[0].pr = 0;
	a[1].mk = 1;
	a[1].pr = 0;
	for(i = 2 ; i <= n ; i++)
	{
		cin >> k >> p;
		a[i].mk = 1;
		if(p == 0)
		{
			a[a[k].pr].ne = i;
			a[i].pr = a[k].pr;
			a[k].pr = i;
			a[i].ne = k;
		}
		else
		{
			a[a[k].ne].pr = i;
			a[i].pr = k;
			a[i].ne = a[k].ne;
			a[k].ne = i;
		}
	}
	cin >> m;
	int x;
	for(i = 1 ; i <= m ; i++)
	{
		cin >> x;
		if(!a[x].mk)
		{
			continue;
		}
		a[x].mk = 0;
		a[a[x].pr].ne = a[x].ne;
		a[a[x].ne].pr = a[x].pr;
	}
	printf("%d",a[0].ne);
	int now = a[0].ne;
	now = a[now].ne;
	while(now)
	{
		printf(" %d",now);
		now = a[now].ne;
	}
	cout << endl;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值