Loading

移动盒子——UVa 12657

问题描述

你有一行盒子,从左到右依次编号为1, 2, 3,…, n。可以执行以下4种指令:

  1. X Y表示把盒子X移动到盒子Y左边(如果X已经在Y的左边则忽略此指令)。
  2. X Y表示把盒子X移动到盒子Y右边(如果X已经在Y的右边则忽略此指令)。
  3. X Y表示交换盒子X和Y的位置。
  4. 表示反转整条链。

指令保证合法,即X不等于Y。例如,当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

想法

此题用双向链表非常好实现,但是蛋疼的是STL有点慢,前一篇悲剧文本——UVA 11988已经说了。如果不熟悉数组模拟链表的建议看看前一篇。

所以还要用数组模拟链表,而且这次是双向链表。

#include "iostream"
#include "cstdio"
#define MAX 100002

using namespace std;

int box_n,cmd_n;
int i;
int cmd,op1,op2,inv;
int _prev[MAX] , _next[MAX];

void link(int l, int r) {
    _next[l] = r;_prev[r] = l;
}

int main() {
    while (scanf("%d %d", &box_n,&cmd_n) != EOF) {
        inv = 0;
        _next[0] = 1;
        _prev[0] = box_n;

        for (i = 1; i <= box_n; i++) {
            _next[i] = (i + 1) %(box_n+1);
            _prev[i] = i - 1;
        }

        for (i = 0; i < cmd_n; i++) {
            scanf("%d", &cmd);
            int nop1, nop2, pop1, pop2;
            if (cmd != 4) {
                scanf("%d %d", &op1, &op2);
                nop1 = _next[op1]; nop2 = _next[op2];
                pop1 = _prev[op1]; pop2 = _prev[op2];
            }
            if (cmd!=3&&inv)cmd = 3 - cmd;
            if (cmd == 1 && _prev[op2] == op1)continue;
            if (cmd == 2 && _next[op2] == op1)continue;

            switch (cmd) {
            case 1:
                link(pop1, nop1);link(pop2, op1); link(op1, op2); 
                break;
            case 2:
                link(pop1, nop1); link(op2, op1);link(op1, nop2); 
                break;
            case 3:
                if (_next[op1] == op2) {
                    link(pop1, op2); link(op2, op1); link(op1, nop2);
                }
                else if (_next[op2] == op1) {
                    link(op2, nop1); link(op1, op2); link(pop2, op1);
                }
                else {
                    link(pop1, op2); link(op1, nop2); link(op2, nop1); link(pop2, op1);
                }
                break;
            case 4:
                inv = !inv;
                break;
            }
        }
        if(!inv)
			for (i = 0; _next[i] != 0; i = _next[i]) {
				printf("%d ", _next[i]);
			}
        else
            for (i = 0; _prev[i] != 0; i = _prev[i]) {
                printf("%d ", _prev[i]);
            }
        printf("\n");
    }
    return 0;
}

这个代码不难,最主要的是去自己推理那些link操作的含义,把它比作真的双向链表,其实挺好看出来(我看了俩小时)。

posted @ 2020-11-04 20:31  yudoge  阅读(121)  评论(0编辑  收藏  举报