• 移动小球 (sicily 1934) (双向链表)


    移动小球

    Constraints

    Time Limit: 1 secs, Memory Limit: 32 MB

    Description

    你有一些小球,从左到右依次编号为1,2,3,...,n. 你可以执行两种指令(1或者2)。其中, 1 X Y表示把小球X移动到小球Y的左边, 2 X Y表示把小球X移动到小球Y右边。 指令保证合法,即X不等于Y。 例如,初始状态1,2,3,4,5,6的小球执行1 1 4后,小球1被移动到小球4的左边,即2,3,1,4,5,6。如果再执行2 3 5,结点3将会移到5的右边,即2,1,4,5,3,6。 

    Input

    第一行为一个整数t(0<t<10),表示测试用例个数。每个测试用例的第一行为两个整数n(1<n<=500000)和m(0<m<100000),n表示小球的个数,m为指令条数,以下m行每行为一条指令。  

    Output

    为每个测试用例单独输出一行,从左到右输出最后序列,每个数字后面跟一个空格。 

    Sample Input

    2 
    6 2 
    1 1 4 
    2 3 5 
    5 1 
    2 1 5 

    Sample Output

    2 1 4 5 3 6  
    2 3 4 5 1  
    -------------------------------------------------------------------------------------------------------------------------------------
    本题如果使用移动数组元素的方法,效率低效,而且必然会超时。由于强调的是小球间的相对顺序,而非绝对顺序。可以用left[i]和right[i]分别表示变化为i的小球的左边和右边的小球编号,移动过程可以分成两个步骤:把X移出序列(take);把X重新插入序列。
     1 #include <cstdio>
     2 
     3 const int maxn=500000+10;
     4 int left[maxn],right[maxn];
     5 void take(int x){//取出x
     6     right[left[x]]=right[x];
     7     left[right[x]]=left[x];
     8 }
     9 void link(int x,int y){//将x插到y的前面
    10     right[x]=y;
    11     left[y]=x;
    12 }
    13 int main(){
    14     int cases,n,m;
    15     int type,x,y;//对应移动命令中的三个数
    16     scanf("%d",&cases);
    17     for(int i=0;i<cases;i++){
    18         scanf("%d%d",&n,&m);
    19         for(int j=1;j<=n;j++) //初始化双向链表
    20             right[j]=j+1,left[j]=j-1;
    21         right[0]=1,left[n+1]=n;
    22 
    23         for(int j=0;j<m;j++){
    24             scanf("%d%d%d",&type,&x,&y);
    25             switch(type){
    26                 case 1:
    27                     take(x),link(left[y],x),link(x,y);
    28                     break;
    29                 case 2:
    30                     take(x),link(x,right[y]),link(y,x);
    31                     break;
    32             }
    33         }
    34         for(int j=0,start=0;j<n;j++){
    35             printf("%d ",right[start]);
    36             start=right[start];
    37         }
    38         printf("
    ");
    39     }
    40     return 0;
    41 }

    思考:一共两种指令,1 X Y将X挪到了Y了左边,2 X Y将X挪到了Y的右边。假设right_Y代表Y右边的球,那么2 X Y是否等价于1 X right_Y?此时如果只实现一个move方法来代替take 和 link方法,并将根据指令移动的那部分代码替换成move方法,此时是否仍然正确?

     1 void move(int x,int y){//将x插到y的前面
     2     right[left[x]]=right[x];
     3     left[right[x]]=left[x];
     4     right[left[y]]=x;
     5     left[x]=left[y];
     6     left[y]=x;
     7     right[x]=y;
     8 }
     9 
    10 switch(type){
    11     case 1:
    12         link(x,y);
    13         break;
    14     case 2:
    15         link(x,right[y]);
    16         break;
    17 }
  • 相关阅读:
    SVM+HOG特征训练分类器
    数字图像处理的基本原理和常用方法
    c++中二进制和整数转化
    目标检测——HOG特征
    相似图片搜索的原理和实现——颜色分布法
    测试文本文件大小
    Direct2D 图形计算
    Direct2D 如何关闭抗锯齿
    MFC窗口显隐
    CISP/CISA 每日一题 22
  • 原文地址:https://www.cnblogs.com/purgiant/p/3203000.html
Copyright © 2020-2023  润新知