洛谷1160 队列安排-简单的链表

295 阅读2分钟

P1160 队列安排

第一版:

  1. 思路:
    1. 使用链表 c++ 的list库
    2. 插入的时候遍历查找,然后插入
    3. 删除的时候使用list.remove()进行删除
  2. 结果:后三个超时
  3. 源码:
#include<iostream>
#include<list>

using namespace std;
list<int> ls;
int n;

int main(){
   // freopen("data.in","r",stdin);
    cin>>n;
    ls.push_back(1);
    int t1,t2;
    list<int>::iterator it;
    for(int i=2;i<=n;i++){
        cin>>t1>>t2;
        for(it=ls.begin();it!=ls.end();it++){
            if(*it==t1){
                if(t2==0){
                    // 左边
                    ls.insert(it,i);
                }else{
                    // 右边
                    ls.insert(++it,i);
                }
                break;
            }
        }
    }
    cin>>n;
    while(n--){
        cin>>t1;
        ls.remove(t1);
    }
    while(!ls.empty()){
        n = ls.front();
        ls.pop_front();
        cout<<n;
        if(ls.size()!=0)
            cout<<" ";
    }
    cout<<endl;
    return 0;
}
  1. 问题分析:
    1. 每次插入都要遍历一遍,插入的时间复杂度O(n^2)
    2. 删除的时候不确定,没去查源码

第二版:

本次解法参考(照抄)了 Orina_zju 的解法,

  1. 思路:

    1. 既然每次插入花费了大量时间,那就想办法减少时间花费,大牛使用一个iterator数组的方法直接记录每个学生对应的iterator,使得insert的时候不需要遍历查找,节省了插入的时间

      插入后的迭代器 insert(迭代器,插入值);
      // 大牛的方法
      ls<int> ls; 
      list<int>::iterator pos[100003];
      pos[新插入的同学的编号] = ls.insert(pos[被插入的同学的编号],新插入的同学的编号)
      // 当新插入的是右边时,可以使用迭代器中的next方法
      pos[新插入的同学的编号] = ls.insert(next(pos[被插入的同学的编号]),新插入的同学的编号)
      

      本蒟蒻这还是第一次接触到迭代器的这些方法...

    2. 删除的时候使用erase(iterator)的方式,由于记录的有每个同学的iterator,所以也省去了遍历的时间

      这里新增了一个数组,记录是否删除过了,因为如果不进行记录,虽然数值不会被重复删除,但是ls的数量会不对,以本体测试用例为例,

          ls.erase(its[3]);
          ls.erase(its[3]);
          cout<<"size is "<<ls.size()<<endl;
          while(!ls.empty()){
              cout<<ls.front()<<endl;
              ls.pop_front();
          }
      /*
      	输出:
          size is 2
          2
          4
          1
      */
      

      所以,需要一个bool数组记录是否删除过

      	bool used[100000+5];// [1,n]初始化为true
          while(n--){
              cin>>t1;
              if(used[t1]){
                 ls.erase(its[t1]);
                  used[t1] = false;
              }
          }
      
  2. 完整代码

    #include<iostream>
    #include<list>
    
    using namespace std;
    list<int> ls;
    list<int>::iterator its[100000+5];
    int n;
    bool used[100000+5];
    
    int main(){
        freopen("data.in","r",stdin);
        cin>>n;
        ls.push_back(1);
        its[1] = ls.begin();
        used[0] = used[1] = true;
        int t1,t2;
        list<int>::iterator it;
        for(int i=2;i<=n;i++){
            cin>>t1>>t2;
            if(t2==0){
                // 左边,正常插入
                its[i] = ls.insert(its[t1],i);
            }else{
                // 右边
                its[i] = ls.insert(next(its[t1]),i);
            }
            used[i] = true;
        }
        cin>>n;
        while(n--){
            cin>>t1;
            if(used[t1]){
               ls.erase(its[t1]);
                used[t1] = false;
            }
        }
        while(!ls.empty()){
            n = ls.front();
            ls.pop_front();
            cout<<n;
            if(ls.size()!=0)
                cout<<" ";
        }
        cout<<endl;
        return 0;
    }