• 洛谷 P1160 队列安排


    【题目链接】

    洛谷 P1160 队列安排

    【题目考点】

    1. 链表(双向链表)
    2. list

    【解题思路】

    解法1:手动实现双向链表

    设数组na,na[i]表示第i名同学对应的结点的地址。na[i]为0表示第i名同学已被移去。
    头插、尾插、插入函数都会返回插入结点的地址,将该地址保存在na数组中。
    双向链表中的insert函数的作用为在地址it指向的元素前插入元素。若需在it指向的元素后插入,则应该先让it指向下一个元素,而后调用insert。
    删除同学,直接调用删除结点的函数erase函数即可。

    解法2:使用STL list

    设数组na,类型为list::iteratorna[i]表示指向第i名同学对应结点的迭代器。na[i]为lis.end()表示第i名同学已被移去。
    其它做法与解法1类似。

    【题解代码】

    解法1:手动实现双向链表
    #include
    using namespace std;
    #define N 100005
    template<class T>
    struct Node
    {
        T val;
        int next, pre;
    };
    template<class T>
    struct List
    {
        Node<T> node[N]; //内存池
        int p; //当前可分配的元素的地址
        int head; //头结点地址
        int tail; //尾结点地址
        List()
        {
            p = 0;
            head = ++p;
            tail = head;
        } 
        int push_front(T d)//头插法 返回插入结点的地址 
        {
            int np = ++p;
            node[np].val = d;
            node[np].next = node[head].next;
            node[np].pre = head;
            node[node[head].next].pre = np;//node[head].next为0,不影响 
            node[head].next = np;
            if(tail == head)
                tail = np;
            return np;
        }
        int push_back(T d)//尾插法 返回插入结点的地址 
        {
            int np = ++p;
            node[np].val = d;
            node[tail].next = np;
            node[np].pre = tail;
            tail = np;
            return np;
        }
        int getAddr(int i)//获取第i个结点的地址(i从1开始数)
        {
            int ip = head; //第i个节点的地址
            for(int j = 1; j <= i; j++)
                ip = node[ip].next;
            return ip;
        }
        int insert(int t, T d)//在t指向的结点前插入结点 返回插入的结点的地址 
        {       
            int np = ++p;
            node[np].val = d;
            node[np].next = t;
            node[np].pre = node[t].pre;
            node[node[t].pre].next = np;
    		node[t].pre = np;
            return np;
        }
        int erase(int t)//删除t指向的结点 返回删除的结点的下一个结点的地址 
        {
        	node[node[t].pre].next = node[t].next;
        	node[node[t].next].pre = node[t].pre;
            if(tail == t)//如果删掉的是尾结点
                tail = node[t].pre; //把尾指针设为前一个结点 
            return node[t].next;
        }
        T get(int t)//获取t指向的结点的值 
        {
        	return node[t].val;
    	}
        int begin()//第一个结点的地址 
        {
            return node[head].next;
        }
        int end()//最后一个结点的下一个结点的地址 
        {
            return 0;
        }
        int next(int t)//t指向结点下一个结点的地址 
        {
            return node[t].next;
        }
        int pre(int t)//t指向结点前一个结点的地址 
        {
            return node[t].pre;
        }
    };
    List<int> li;
    int pos[N];//pos[i]:第i号同学的地址 
    int main()
    {
        int n, k, p, t, np, m, x;
        cin >> n;
        pos[1] = li.push_front(1);//1号同学进队列 
        for(int i = 2; i <= n; ++i)
        {
            cin >> k >> p;
            if(p == 0)//k左边插入 
                np = li.insert(pos[k], i);//在第k号同学结点地址pos[k]左边插入值i 
            else//k右边插入 
            {
                if(li.next(pos[k]) == li.end())//如果k的下一个结点是end(),说明k是最后一个结点,需要用尾插法将i插到k右边 
                    np = li.push_back(i);
                else//k下一个结点的左边插入i
                    np = li.insert(li.next(pos[k]), i);
            }
            pos[i] = np;//记录第i号同学的结点地址是np 
        }
        cin >> m;//m次删除 
        for(int i = 1; i <= m; ++i)
        {
            cin >> x;//删除x号同学 
            if(pos[x] > 0)//若pos[x]为0,则说明x号学生被移除了。避免重复删除。 
            {
                li.erase(pos[x]);
                pos[x] = 0;
            }
        }
        for(int i = li.begin(); i != li.end(); i = li.next(i))//遍历链表 输出 
            cout << li.get(i) << ' ';
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    解法2:
    #include 
    using namespace std;
    typedef list<int>::iterator It;
    #define N 100005
    It na[N];//na[i]:指向表示第i同学结点的迭代器 na[i]为lis.end(),则表示第i同学已经不在队列之中 
    list<int> lis;
    int main()
    {
    	int n, k, p, t, m, x;
    	It ip;
    	cin >> n;
    	lis.push_back(1);//添加第1名同学 
    	na[1] = lis.begin();
    	for(int i = 2; i <= n; ++i)
    	{
    		cin >> k >> p;
    		ip = na[k];//指向第k号同学的迭代器 
    		if(p == 1)//如果在第k号同学右面插入 
    			ip++;//那么ip加1后,在ip指向的结点左边插入 
    		na[i] = lis.insert(ip, i);//在ip指向的结点左边插入值为i的新结点,指向该结点的迭代器保存在na[i]
    	}
    	cin >> m;
    	for(int i = 1; i <= m; ++i)
    	{
    		cin >> x;
    		if(na[x] != lis.end())//如果第x号同学还在队列内 
    		{
    			lis.erase(na[x]);//删掉第x号同学 
    			na[x] = lis.end();//na[x]设为lis.end()表示第x号同学已经不在队列内 
    		}
    	}
    	for(It it = lis.begin(); it != lis.end(); it++)//遍历list,输出链表 
    		cout << *it << ' ';
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
  • 相关阅读:
    Nacos安装指南
    mongostat性能分析
    2021秋招---leetcode-总结
    R语言ggplot2可视化:基于aes函数中的fill参数和shape参数自定义绘制分组折线图并添加数据点(散点)、设置可视化图像的主题为theme_bw
    最佳开源DEM全国、省、市、县DEM数据分享
    使用vscode操作本地git
    面试:ThreadLocal相关
    Python + ESP32 DIY自动感应智能皂液器 避免触摸更安全
    Kylin ext3/4 xfs手动扩容根分区
    学习C++第二十课--对象移动、移动构造函数与移动赋值运算符笔记
  • 原文地址:https://blog.csdn.net/lq1990717/article/details/127429719