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 2 3 4 5 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。
【输入格式】
输入包含不超过10组数据,每组数据第一行为盒子数n和指令m,以下m行每行包含一条指令。
【输出格式】
每组数据输出一行,即所有奇数位置的盒子编号之和。位置从左到右编号为1~n。
整个题的题意非常简明扼要,就是一个顺序链表,要求在一定模拟操作后,求奇数位置的情况,但是如果继续使用单向链表来解决我们很难改变xy和位置,因为单向链表中,我们无法表示这个链的顺序,所以我们采用双向链表的方式解决问题
也就是对每个位置设置right和left两个值,表示该位置的左右分别是什么
使用link函数表示a和b接起来
对于 指令3 ,即交换指令,它不受flag 的影响,但是交换的过程却和 X 与 Y 的相对位置有关:
- 如果 X 和 Y 不相邻,那么 可以 通过以下步骤完成交换:
link(LX,Y),link(Y,RX),link(LY,X),link(X,RY); - 如果X 和 Y 相邻,那么又可以分成两种情况:
1 X 在 Y 的左边:link(LX,Y),link(Y,X),link(X,RY)。
2Y 在 X 的左边:link(LY,X ),link(X,Y),link(Y,RX)。
观察以上两种情况,我们可以预处理X,Y,使得 X 始终在 Y的左边,具体而言就是当发现Y 在 X 的左邻时,交换Y 和 X 即可,这样,情况就统一为 1。 - 接下来我们观察可以发现操作四并不需要真的执行,如果链处于反转状态我们只需把1-2指令互换就可以得到相应的结果了所以在前置操作中通过if(a!=3&&inv){a=3-a;}来改变a的具体数值
处理完细节后,我们只需按要求队程序进行顺序模拟,用link函数按顺序进行操作就可以模拟出操作后的链表
需要注意的是,如果表的个数是偶数并且表处于反装状态,在最后求解时需要用所有位置的和减去奇数的和,才能得到真正的奇数位置的和。

1 #include<bits/stdc++.h> 2 using namespace std; 3 int right1[100005],left1[100005]; 4 void link(int x,int y) 5 { 6 right1[x]=y; 7 left1[y]=x; 8 } 9 int main() 10 {int case1=0; 11 int n,m,inv=0,a,b,c; 12 while(scanf("%d%d",&n,&m)==2) 13 {inv=0; 14 for(int i=1;i<=n;i++)//初始化链表连接 15 { 16 right1[i]=(i+1)%(n+1); 17 left1[i]=i-1; 18 } 19 right1[0]=1;left1[0]=n; 20 for(int i=1;i<=m;i++) 21 { 22 cin>>a; 23 if(a==4) 24 inv=!inv; 25 else { 26 cin>>b>>c; 27 if(a==3&&right1[c]==b)swap(b,c); 28 if(a!=3&&inv){a=3-a;} 29 if(a==1&&left1[c]==b)continue; 30 if(a==2&&right1[c]==b)continue; 31 int lx=left1[b],ly=left1[c],rx=right1[b],ry=right1[c]; 32 if(a==1) 33 { 34 link(lx,rx); 35 link(ly,b); 36 link(b,c); 37 } 38 else if(a==2) 39 { 40 link(lx,rx); 41 link(c,b); 42 link(b,ry); 43 } 44 else if(a==3) 45 { 46 link(lx,c); 47 link(c,rx); 48 link(ly,b); 49 link(b,ry); 50 } 51 } 52 } 53 int q=0,ans=0; 54 for(int i=1;i<=n;i++) 55 { 56 q=right1[q]; 57 if(i%2==1)ans+=q; 58 } 59 if(inv&&n%2==0)ans=(long long)n*(n+1)/2-ans; 60 cout<<"Case "<<++case1<<": "<<ans<<endl; 61 } 62 return 0; 63 }