算法訓練-移動小球
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