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          } 
View Code

 

posted @ 2020-09-19 03:11  徒手拆机甲  阅读(178)  评论(0)    收藏  举报