p1160队列安排原题链接:队列安排 - 洛谷
这一题很显然是考链表的知识点,这里我是用结构体数组和STL的list容器两种方法实现。
ps:可以直接看最下面的代码
结构体数组实现的过程:
下面是对题目的分析(两种方式是一样的思路):
首先创建一个有"L"和"R"的结构体(下标i即代表第i个),用来表明每一个i左右边连接的数。
并且L和R都赋初始值为0,值为0就像指向空。
在一开始创建完结构体后大概长这样:
因为是用数组来表现链式结构,所以我们不知道在最终排完队后谁是第一个同学,所以可以用一个"head"来表示排在第一个的同学。
这一句即是把"head"赋值为1,但不会改变上图。
这一句我们用一个for循环就可以解决,for中的i从2开始。
这里说明有删除操作,并且结合下面的输入说明和样例得知,同一个数可能被删除多次,所以为了防止删除同一个数字而导致的其他问题,这里可以用一个数组来表示这个同学是否有被删除过,在开始删除前,可以把数组全部赋值为1,表示没被删除。
了解完大概题意后能大概得到下面这个框架:
const int N = 100005;
struct node {
int l = 0, r = 0;
}L[N];
int h[N];
int main() {
int n, m, head = 1;//初始化头节点为第一个同学
cin >> n;
memset(h, 1, sizeof(h));//h数组用来检查第i个同学有没有被删除,置1。
int k, p;
for (int i = 2; i <= n; ++i) {
scanf("%d %d", &k, &p);
}
return 0;
}
然后根据输入说明
我们开始写for循环里的内容,
这是适用普通情况的,但我们还需要考虑p==0时,k的左边还有同学,也就是i插在两个同学之间,这时我们就要考虑i和k左边的那个同学的关系了。以样例说明,在执行完i=3两个操作后,为下图的黑色部分,而在i=4(k=1,p=0)的时候,我们不仅要修改i和k的关系,也要修改L[L[k].l].r和i的关系,如下图:
所以,在p==0的时候需要先判断k的左边是否还有同学,当左边还有同学的时候,我们应该先修改k左边的同学和i的关系,
注意这里的这个if(L[k].l)必须先写,如果是先写了i和k的关系修改,那样L[k].l就等于i了,就找不到原本k左边的同学了。当p==1时,步骤和这里是一样的。
此外,在p==0的时还有注意head的变化,当我们要在k的左边插入i,k原本又是排在最左边的,我们就需要将head=i了。 在执行完for语句后,结构体数组变成下面这样:
然后是删除操作,我们前面创建了一个h数组用于判断是否被删除,于是我们可以用一个if(h[cur])就可以判断是否要删除它了,在这里可以先用一个tmp来记录L[cur].l,这样是为了修改要删除的数的右边的那个数的左边,也就是L[L[cur].r].l的值。这里我们也要注意头节点head的变化,当我们删除的当前节点cur就是头节点时,我们要把头节点传给cur右边的的节点:head=L[cur].r。
最后,我们用一个循环来输出队伍,并且初始的i=head,每次让i=L[i].r,当i==0时退出即可。
具体代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<list>
#include<cstring>
#include<string>
using namespace std;
const int N = 100005;
struct node {
int l = 0, r = 0;
}L[N];
int h[N];
int main() {
int n, m, head = 1;//初始化头节点为第一个同学
cin >> n;
memset(h, 1, sizeof(h));//h数组用来检查第i个同学有没有被删除,置1。
int k, p;
for (int i = 2; i <= n; ++i) {
scanf("%d %d", &k, &p);
if (p == 0) {
if (L[k].l) {//如果k同学左边还有同学
L[L[k].l].r = i;//先修改k左边的同学的右边为i
L[i].l = L[k].l;
}
L[i].r = k;//注意不能写在if (L[k].l)前。
L[k].l = i;
if (head == k) {//k为头节点的话,i又插入在k左边,则将head=i;
head = i;
}
}
else {
//同上
if (L[k].r) {
L[L[k].r].l = i;
L[i].r = L[k].r;
}
L[i].l = k;
L[k].r = i;
}
}
cin >> m;
int cur;
while (m--) {
scanf("%d", &cur);
if (h[cur]) {//cur没有被删除
int tmp = L[cur].l;
if (L[cur].l) {
L[L[cur].l].r = L[cur].r;
}else {//如果左边没有节点,则需要修改头节点
head = L[cur].r;
}
if (L[cur].r) {
L[L[cur].r].l = tmp;
}
h[cur] = 0;
}
}
for (int i = head; i != 0; i = L[i].r) {
printf("%d ", i);
}
return 0;
}
用list实现:
#include <list>
#include<iostream>
using namespace std;
const int N = 100005;//注意N的范围是1e5
list<int>::iterator pos[N];
list<int> queList;
int h[N];
int main()
{
int N;
scanf("%d", &N);
queList.push_front(1);
pos[1] = queList.begin();
for (int i = 2; i <= N; i++)
{
int k, p;
scanf("%d%d", &k, &p);
if (p == 0)
{
pos[i] = queList.insert(pos[k], i);
}
else
{
list<int>::iterator nextIter = next(pos[k]);
pos[i] = queList.insert(nextIter, i);
}
}
int M;
cin >> M;
for (int i = 1; i <= M; i++)
{
int x;
cin >> x;
if (!h[x]) {
h[x] = 1;
queList.erase(pos[x]);
}
}
list<int>::iterator it = queList.begin();
for (int i = 1; i <= queList.size(); i++)
{
cout << *it << " ";
it++;
}
return 0;
}