zoukankan      html  css  js  c++  java
  • Sicily课程作业 1934. 移动小球

    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  


    解题思路:一开始是考虑使用双向链表来做,虽然插入和删除的操作都会很方便,但这样会出现查找的花费的时间太长(要查找firstball和secondball的位置)。事实确实如此,采用双向链表来做最终超时了(当然也可能是代码出现了死循环的情况,如果你用双向链表AC了,可以分享一下你的代码)。百度一下,发现很强大的方法,开一个数组记录每个小球的左右小球的编号,模拟双向链表,这样就实现了随机访问而不需要遍历。思考之后决定使用数组模拟双向循环链表,之所以采用循环的结构是因为这样的话,就不需要考虑操作首尾部分小球时候,导致的特殊情况,更加方便。然后声明一个变量来记录每次操作之后首位小球的编号,这样输出也就有着落了。代码有详细注释,具体可参考代码如下。
    代码+注释:
    #include <iostream>
    #include <stack>
    #include <string>
    
    using namespace std;
    class ball{
    public:
        int left;
        int right;
    };
    ball array[500001];//大数组不能放在main()内
    
    void moveball(int order,int first,int second,ball array[]){//移动操作的函数
       if(order == 1){
          array[array[first].left].right  = array[first].right;
          array[array[first].right].left = array[first].left;
          array[first].left = array[second].left;
          array[first].right = second;
          array[array[second].left].right = first;
          array[second].left = first;
       }
       else{
          array[array[first].left].right  = array[first].right;
          array[array[first].right].left = array[first].left;
          array[first].left = second;
          array[first].right = array[second].right;
          array[array[second].right].left = first;
          array[second].right = first;
       }
    }
    int main(){
        int i,txcase,numofball,commandnum, order,first,second;
        cin >> txcase;
         
        while(txcase--){
          int head = 1;//head用来跟踪表头,默认初始化为1
            cin >> numofball >> commandnum;
            //接下来采用数组模拟双向循环链表,循环的话就可以免去在头和尾操作的特殊情况
          array[1].left = numofball;//初始化表头
          array[1].right = 2;
    
          array[numofball].left = numofball - 1;//初始化表尾
          array[numofball].right = 1;
    
          for(i = 2;i < numofball;i++){//初始化循环链表
             array[i].right = i+1;
             array[i].left = i-1;
          }
    
          while(commandnum--){//移动小球操作
            cin >> order >> first >> second;
            
            if(head == first && !(order == 1 && second == array[first].right)){//当第一个小球是表头时,只有第二个球刚好是下一个且命令是左插入表头才不会改变
               head = array[head].right;
               moveball(order,first,second,array);
            }
            else if(order == 1 && second == head){//当第二个小球为头,且在左插入时表头改变
               head = first;
               moveball(order,first,second,array);
            }
            else
              moveball(order,first,second,array);
          }
    
          //所有order执行完毕之后输出
          for(i = 0;i < numofball-1;i++){
            cout << head <<" ";
            head = array[head].right;
          }
          cout << head << endl;
        }
          system("pause");
        return 0;;
    }
     
  • 相关阅读:
    Seasar2:SAStruts:View(JSP)
    Seaser2:SAStruts:エラーメッセージの設定
    Seaser2:SAStruts:アクションとアクションフォーム(Struts)
    SAStruts アクションにJSONを返すメソッドを作成してみる
    S2JDBC テーブルを利用した独自仕様のid採番メソッド
    【C++ 异常】error: jump to case label [fpermissive]
    MusicXML 3.0 (15) 倚音
    MusicXML 3.0 (9) 小节线、反复线、终止线
    MusicXML 3.0 (13) 歌词
    MusicXML 3.0 (10) 换行、换页
  • 原文地址:https://www.cnblogs.com/nomonoyumei/p/3487588.html
Copyright © 2011-2022 走看看