Boxes in a Line UVA - 12657(双向链表)

题目:

有N个盒子排成一列,从左至右编号1~n,现有四种操作,分别如下:
1 X Y 将编号为X的盒子置于编号为Y的盒子的左边(相邻)
2 X Y 将编号为X的盒子置于编号为Y的盒子的右边(相邻)
3 X Y 将编号为X的盒子和编号为Y的盒子交换位置
4 反转整个排列
在M次操作之后,求坐标为奇数的盒子,其编号之和
例如,如果n = 6,则在执行1 1 4之后,该行变为2 3 1 4 5 6。 然后在执行2 3 5之后,该行变为2 1 4 5 3 6。 然后在执行3 1 6之后,该行变为2 6 4 5 3 1。 然后在执行4之后,行变为1 3 5 4 6 2。此时所求为1 + 5 + 6 = 12

/(ㄒoㄒ)/~~

考察链表,简单的使用数组是不明智的,第一次写用结构体完成了纯 · 双向链表,代码老长老长,还好AC了,文章最后放代码。
然后呢,就想用 list 模拟一下链表,但事情并没有那么简单:
本题如果不加思考直接写,肯定会超时,因为在查找,插入,反转上会浪费很多时间但是最坑的是这三个中任何一个不优化,都会超时
第一步优化:我们放弃查找,转而动态记录每个盒子的位置
第二步优化:如上操作,交换只需要交换值和迭代器,因为交换意味着交换盒子以及盒子的位置,少一个都不行(list.reverse也不行,我还是天真了)
第三步优化:插入时,寻址插入就好,记录迭代器就给我们提供了方便
小心溢出

实现:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <list>
using namespace std;
int main() {
    int n, k, op, a, b, cp = 1;
    for(; cin >> n >> k; cp++) {

        list<int> L(n);
        list<int>::iterator it;
        vector<list<int>::iterator> IT(n+1); //用来记录盒子的位置 IT[0]是用不到的

        int i = 1;
        for (it = L.begin(); it != L.end(); it++, i++) {
            *it = i; //这个赋值方法挺好的
            IT[i] = it;
        }

        int fp = 0; //用来标记反转与否
        while(k--) { scanf("%d", &op);

            if(op == 4) {
                if(fp) fp = 0; else fp = 1;
                continue;
            }
            scanf("%d%d", &a, &b);
            if(op == 3) swap(*IT[a], *IT[b]), swap(IT[a], IT[b]); //缺一不可哦
            else {
                L.erase(IT[a]); //L.remove(a) 也是可以的
                if(!fp && op == 1 || fp && op == 2) //注意条件
                    IT[a] = L.insert(IT[b], a);
                else {it = IT[b]; IT[a] = L.insert(++it, a);} 
            }   //如果插在右侧  迭代器要下走一位
        }
        long long ans = 0;  //overflow...
        if(fp) fp = 0; else fp = 1;
        for(it = L.begin(); it != L.end(); fp++, it++)
            if(fp % 2) ans += *it;
        printf("Case %d: %lld\n", cp, ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值