Uva12657 Boxes in a Line 【双向链表】【例题6-5】

题目:Boxes in a Line

题意:移动盒子,有4种操作:

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

最后计算所有奇数位置的盒子编号之和。

思路:利用双向链表,Left[i]代表编号i盒子左边的盒子编号,Right[i]代表编号i盒子右边盒子的编号。

当操作1时:X移到Y的左边:

例如:1 2 3 4 5 6

           将1移到4的左边为:2 3 1 4 5 6

           此时发生变化的有(1)1的左边和右边  ,(2)2的左边和右边  ,(3)3 的右边 ,(4)4的左边

俩个结点相互连接:void Link(int L,int R){Right[L] = R ;Left[R] = L;};

起初的Left[] = {6,0,1,2,3,4,5 } , Right[] = {1,2,3,4,5,6,0}

x = 1,y = 4

lx = Left[x],rx = Right[x],ly = Left[y],ry = Right[y];  

所以有:Link(lx,rx);--->0原本右边是1,而1要移走,所以0的右边改为2;2原本左边是1,而1要移走,所以2 的左边改为0。

                Link(ly,x); --->3原本右边是4,而1将插入,所有3的右边改为1;1原本左边是0,而1新插入,左边是3,所以,1的左边改为3。

                Link(x,y); --->1原本的右边是2,而1新插入位置后,右边为4,所以该为4;而4原本的左边为3,而当前插入了1,所以4的左边改为1。

其他同理即可!

参考:入门经典--例题6-5--P145

代码:

#include <iostream>
#include <cstdio>
#define MAXN 100005
using namespace std;
int n,Left[MAXN],Right[MAXN];
void link(int L,int R)
{
    Right[L] = R;
    Left[R] = L;
}
int main()
{
    
    int m,kase = 0;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(int i=1;i<=n;i++)
        {
            Left[i] = i-1;
            Right[i] = (i+1) % (n+1);
        }
        Right[0] = 1;Left[0] = n;
        int op,x,y,inv = 0;
        while(m--)
        {
            scanf("%d",&op);
            if(op == 4)
                inv = !inv;
            else
            {
                scanf("%d%d",&x,&y);
                if(op == 3 && Right[y] == x) swap(x,y);
                if(op != 3 && inv) op = 3 - op;
                if(op == 1 && x == Left[y]) continue;
                if(op == 2 && x == Right[y]) continue;

                int lx = Left[x],rx = Right[x],ly = Left[y],ry = Right[y];
                if(op == 1)//将X移到Y的左边
                {
                    link(lx,rx);//X要发生改变,所以X的左值的后一个和右值的前一个也会发生变化,左值的右值为x的右值,右值的左值为x的左值
                    link(ly,x);//同理,Y的左值的右值发生变化,为新插入的X值,当前X的左值也变为Y的左值
                    link(x,y);//同理,新插入的X的右值为Y,Y的左值改变为X!
                }
                else if(op == 2)
                {
                    link(lx,rx);//同理
                    link(y,x);
                    link(x,ry);
                }
                else if(op == 3)
                {
                    if(Right[x] == y)
                    {
                        link(lx,y);//同理
                        link(y,x);
                        link(x,ry);
                    }
                    else
                    {
                        link(lx,y);//同理
                        link(y,rx);
                        link(ly,x);
                        link(x,ry);
                    }
                }
            }
        }
        int b = 0;
        long long ans = 0;
        for(int i=1;i<=n;i++)
        {
            b = Right[b];
            if(i % 2)
                ans += b;
        }
        if(inv && n % 2 == 0)//当翻转时是将总个数减去计算出的奇数和
            ans = (long long)n*(n+1)/2 - ans;
        printf("Case %d: %lld\n",++kase,ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值