【刷题】移动盒子问题

【题目】

盒子编号1,2,3...n。

可执行四种指令:
1XY 表示把盒子X移动到盒子Y左边(若X已经在Y的左边则忽略指令)
2XY表示把盒子X移动到盒子Y右边(若X已经在Y的右边则忽略指令)
3XY表示交换盒子X和Y的位置
4表示反转整条链
指令保证合法,X不等于Y。
输入:
每组数据第一行为盒子个数n和指令条数m,以下m行每行包括一条指令,每组数据输出一行,即所有奇数未知的盒子编号之和,位置从左到右编号为1~n。
样例输入:
6  4
1  1  4
2  3  5
3  1  6
4
6  3
1  1  4
2  3  5
3  1  6
10000  1
4
样例输出:
Case 1: 12
Case 2:9

Case 3:2500050000



【原始代码】

拿链表写的,很简单的链表操作。篇幅很大。

#include<iostream>  
using namespace std;  
int bigflag = 0;  
struct node {  
    int x;  
    node * next;  
};  
int main() {  
    int n, m;  
    while (cin >> n >> m)  
    {  
        node *head = new node;;  
        head->x = 1;  
        node *temp = head;  
        for (int i = 2; i <= n; i++) {  
            node *p = new node;  
            p->x = i;  
            temp->next = p;  
            temp = p;  
        }  
        temp->next = NULL;  
        int a, b, c;  
        for (int flag = 0; flag < m; flag++) {  
            cin >> a;  
            if (a == 1) {  
                cin >> b >> c;  
                int i, j;  
                node *zz = head;  
                node *hh = head;  
                if (zz->x == b)i = 0;  
                else {  
                    for (i = 1; i < n; i++) {  
                        if (zz->next->x == b)break;  
                        zz == zz->next;  
                    }  
                }//真实位置i+1,要单独考虑在头的情况;  
                if (hh->x == c)j = 0;  
                else {  
                    for (j = 1; j < n; j++) {  
                        if (hh->next->x == c)break;  
                        hh = hh->next;  
                    }  
                }//真实情况j+1;  
                if (i + 1 + 1 != j + 1) {  
                    if (i == 0) {  
                        head = zz->next;  
                        zz->next = hh->next;  
                        hh->next = zz;  
                    }  
                    else {  
                        node *s = new node;  
                        s = zz->next;  
                        zz->next = zz->next->next;  
                        s->next = hh->next;  
                        hh->next = s;  
                    }  
                }  
                node * w = head;  
            }  
            else if (a == 2) {  
                cin >> b >> c;  
                int i, j;  
                node *zz = head;  
                node *hh = head;  
                if (zz->x == b)i = 0;  
                else {  
                    for (i = 1; i < n; i++) {  
                        if (zz->next->x == b)break;  
                        zz == zz->next;  
                    }  
                }//真实位置i+1,要单独考虑在头的情况;  
                for (j = 1; j < n; j++) {  
                    if (hh->x == c)break;  
                    hh = hh->next;  
                }  
                if (i + 1 != j + 1) {  
                    if (i == 0) {  
                        head = zz->next;  
                        zz->next = hh->next;  
                        hh->next = zz;  
                    }  
                    else {  
                        node *p = new node;  
                        p = zz->next;  
                        zz->next = zz->next->next;  
                        p->next = hh->next;  
                        hh->next = p;  
                    }  
                }  
            }  
            else if (a == 3) {  
                cin >> b >> c;  
                node *zz = head;  
                node *hh = head;  
                int i, j;  
                for (i = 1; i < n; i++) {  
                    if (zz->x == b)break;  
                    zz = zz->next;  
                }  
                for (j = 1; j < n; j++) {  
                    if (hh->x == c)break;  
                    hh = hh->next;  
                }  
                int temp;  
                temp = zz->x;  
                zz->x = hh->x;  
                hh->x = temp;  
                node * e = head;  
                int sum = 0;  
            }  
            else if (a == 4) {  
                node *mid = head;  
                node *tail = head->next;  
                for (int i = 1; i < n; i++) {  
                    node *pre = tail->next;  
                    tail->next = mid;  
                    mid = tail;  
                    tail = pre;  
                }  
                node *mm = mid;  
                head = mid;  
            }  
        }  
        node *mark = head;  
        int sum = 0;  
        for (int i = 1; i <= n; i = i + 2) {  
            sum = sum + mark->x;  
            mark = mark->next->next;  
        }  
        cout << "Case "<<bigflag+1<<": "<<sum << endl;  
        bigflag++;  
    }  
    system("pause");  
    return 0;  
}  
【标准代码】(书上给的答案,有些地方我嫌麻烦稍微修改了下)

#include<iostream>
using namespace std;
int leftt[100001], rightt[1000001];
void link(int l, int r) {
	rightt[l] = r;
	leftt[r] = l;
}
int main() {
	int n, m;
	cin >> n >> m;
	for (int i = 1; i <= n; i++) {
		leftt[i] = i - 1;
		rightt[i] = (i + 1) % (n + 1);
	}
	leftt[0] = n;
	rightt[0] = 1;//非常简单的双向链表,重点在于箱子编号有序,这样很好写,箱子编号如果无序,这个链表也难写出来。
	//标注头尾
	int op, x, y;
	bool mark = false;
	for (int ii = 0; ii < m; ii++) {
		cin >> op;
		if (op != 4) {
			cin >> x >> y;
			int ly = leftt[y], lx = leftt[x], ry = rightt[y], rx = rightt[x];
			if (op == 1 && (leftt[y] != x)) {
				link(lx, rx);
				link(ly, x);
				link(x, y);
			}
			else if (op == 2 && (rightt[y] != x)) {
				link(lx, rx);
				link(y, x);
				link(x, ry);
			}
			else if (op == 3) {
				int tempry = ry;
				int temply = ly;
				link(lx, y);
				link(y, rx);
				link(temply, x);
				link(x, tempry);
			}//这个地方需要留心,前两种情况都是只动一个,现在是动两个。
			else;
		}
		else {
			mark = !mark;
		}
	}
	//现在就是找出奇数位置了
	int flag = 0;
	long long int total = 0;
	for (int i = 1; i <= n; i++) {
		flag = rightt[flag];
		if (i % 2 == 1)total = total + flag;
	}
	if (mark && (n % 2 == 0))total = (long long)n*(n + 1) / 2 - total;
	cout << "Case " << 1 << " : " << total << endl;
	system("pause");
	return 0;
}
篇幅明显缩短。

1首先是箱子编号有顺序,这样用两个数组代替双向链表非常巧妙!!!(这也是这道题其实很水但是一定要po出来的原因)

2反转在单链表里写起来也很麻烦,在这里可以看出他找到了两条规律,(1)反转命令在前三条命令前或者三条命令后都没有关系(所以我们把它统一放在最后处理)

(2)不要求全部输出反转链表,只是求奇数位置之和。用单向链表必须完全反转(不然无法得到奇数位置的盒子编号)双向链表也比较麻烦,数组自带左右位置,不需要反转,找到值的规律,n为奇数反转得到的和还是这些奇数的和,n为偶数反转结果就是总和(1到n)减去结果。(大大节省时间,非常秒!)

(3)数组第0个位置用来存储首尾!!!这样在定位奇数位置的时候非常方便。


非常简洁强大的双链表数组实现(自带左右,标记头尾,注意赋值的时候也挺重要。)

不一定要实现每一条命令,根据题目去寻找规律会简化很多。


其实已经算一个双向循环链表了。

用到【双向or循环链表】并且不删除元素的时候考虑。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值