CCF----學生排隊
PS:此文章已在我的站點更新,請移步訪問~更多注釋講解哦。https://www.jeson.xin/ccf-student_queuing.html // 即將失效。。。
題目
問題描述
體育老師小明要將自己班上的學生按順序排隊。他首先讓學生按學號從小到大的順序排成一排,學號小的排在前面,然后進行多次調整。一次調整小明可能讓一位同學出隊,向前或者向后移動一段距離后再插入隊列。
例如,下面給出了一組移動的例子,例子中學生的人數為 8 人。
- 初始隊列中學生的學號依次為 1, 2, 3, 4, 5, 6, 7, 8;
- 第一次調整,命令為“3號同學向后移動2”,表示3號同學出隊,向后移動2名同學的距離,再插入到隊列中,新隊列中學生的學號依次為 1, 2, 4, 5, 3, 6, 7, 8;
- 第二次調整,命令為“8號同學向前移動3”,表示8號同學出隊,向前移動3名同學的距離,再插入到隊列中,新隊列中學生的學號依次為 1, 2, 4, 5, 8, 3, 6, 7;
- 第三次調整,命令為“3號同學向前移動2”,表示3號同學出隊,向前移動2名同學的距離,再插入到隊列中,新隊列中學生的學號依次為 1, 2, 4, 3, 5, 8, 6, 7。
小明記錄了所有調整的過程,請問,最終從前向后所有學生的學號依次是多少?
請特別注意,上述移動過程中所涉及的號碼指的是學號,而不是在隊伍中的位置。在向后移動時,移動的距離不超過對應同學后面的人數,如果向后移動的距離正好等於對應同學后面的人數則該同學會移動到隊列的最后面。在向前移動時,移動的距離不超過對應同學前面的人數,如果向前移動的距離正好等於對應同學前面的人數則該同學會移動到隊列的最前面。
輸入格式
輸入的第一行包含一個整數n,表示學生的數量,學生的學號由1到n編號。
第二行包含一個整數m,表示調整的次數。
接下來m行,每行兩個整數p, q,如果q為正,表示學號為p的同學向后移動q,如果q為負,表示學號為p的同學向前移動-q。
輸出格式
輸出一行,包含n個整數,相鄰兩個整數之間由一個空格分隔,表示最終從前向后所有學生的學號。
樣例輸入
8
3
3 2
8 -3
3 -2
樣例輸出
1 2 4 3 5 8 6 7
評測用例規模與約定
對於所有評測用例,1 ≤ n ≤ 1000,1 ≤ m ≤ 1000,所有移動均合法。
分析
移動只需要把對應位置的學號進行模擬移動即可。但是有一點就是如何快速知道學生對應的位置在哪(問題關鍵:快速定位)。
一定有一個數組記錄對應位置站的是誰(即排隊序列),此處加入一個數組記錄對應學號的位置,即可快速知道學生位置在哪,進行對應的移動即可。
代碼
1 #include<iostream> 2 using namespace std; 3 int s_p[1005],p_s[1005]; 4 //一個數組存儲學生(學號)對應的位置信息,一個數組存儲位置對應學號 5 void move(int s,int p){ //s->學生學號 p->需要移動的步數 6 int step = p>0 ? 1 : -1; //step記錄是前進還是后退 7 int sp = s_p[s]; //sp->學生s的位置,移動學號的起點 8 s_p[s] += p; //更新學生s記錄的位置,同時也是移動學號的終點位置 9 for(int i=sp; i!=s_p[s]; i+=step){ 10 p_s[i] = p_s[i+step]; //更新位置對應的學號 11 s_p[p_s[i]] -= step; //更新學號對應的位置 12 } 13 p_s[s_p[s]] = s; //當移動完其他學生后,在將學生s插入完成全部移動 14 } 15 int main(){ 16 int n,m; 17 cin >> n >> m; 18 for(int i=1; i<=n; ++i){ 19 p_s[i] = i; 20 s_p[i] = i; 21 } 22 while(m--){ 23 int x,y; 24 cin >> x >> y; 25 move(x,y); 26 } 27 cout << p_s[1]; 28 for(int i=2; i<=n; ++i) 29 cout << " " << p_s[i]; 30 cout << endl; 31 }