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

来源:互联网 发布:java重定向设置cookie 编辑:程序博客网 时间:2024/06/01 07:20

题目: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 100005using 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;}


0 0