算法訓練-移動小球
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
Copy sample input to clipboard
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
本題訓練的是鏈表的思想,鏈表對於刪除與插入還有數字順序對調十分方便
(裏麵沒有用指針,隻用了結構體。比較好理解,指針目前不太會用)
AC代碼:
#include<stdio.h> struct mode { int L,R; int num; }a[2000];//結構體,L,R分別是a[i]的左邊和右邊的數,a[i].num是a[i]本身的值 void Move(int stap,int x,int y) { if(stap==1)//模式1(將x移向y的左邊) { a[a[x].R].L=a[x].L;//x的右邊的左邊等於x原來的左邊 a[a[x].L].R=a[x].R;//x的左邊的右邊等於x原來的右邊 a[x].L=a[y].L;//x的左邊等於y原來的左邊 a[a[y].L].R=a[x].num;//y原來的左邊的右邊變成x a[x].R=a[y].num;//x的右邊變成y a[y].L=a[x].num;//y的左邊變成x return; } else if(stap==2)//模式2(將x移向y的右邊) { a[a[x].R].L=a[x].L;//x的右邊的左邊等於x原來的左邊 a[a[x].L].R=a[x].R; //x左邊的右邊等於x原來的右邊 a[y].L=a[x].R;//y的左邊等於x原來的右邊 a[x].L=a[y].num;//x的左邊等於y a[x].R=a[y].R;//x的右邊等於y原來的右邊 a[y].R=a[x].num;//y的右邊等於x return; } } int main() { int i,j,n,sum,m,stap,x,y,k,first; scanf("%d",&n); while(n--) { scanf("%d%d",&sum,&m); for(i=1;i<=sum;i++)//初始化數組 { a[i].num=i; a[i].L=i-1; a[i].R=i+1; } while(m--) { scanf("%d %d %d",&stap,&x,&y); Move(stap,x,y);//進行調換 } for(i=1;i<=sum;i++) { if(a[i].L==0)//誰的左邊是0,誰第一個輸出 first=i;//標記第一個輸出的數 } k=0; while(k<=sum) { if(k==0)//第一次輸出 { //不輸出左邊的0(因為原來就沒有o) printf("%d ",a[first].num); printf("%d ",a[first].R); k+=3;//下次的那個數沒有計算,這裏要加3而不是2 first=a[first].R; } else { printf("%d ",a[first].R); k++;//每輸出一個數k加一次,知道k滿足數組的長度退出 first=a[first].R; } } printf("\n"); } return 0; }
代碼為原創,轉載請注明出處!
最後更新:2017-04-03 12:55:39