題目
問題描述
鑰匙盒一共有 N個掛鈎,從左到右排成一排,用來掛 N個教室的鑰匙。一串鑰匙沒有固定的懸掛位置,但鑰匙上有標識,所以老師們不會弄混鑰匙。
每次取鑰匙的時候,老師們都會找到自己所需要的鑰匙將其取走,而不會移動其他鑰匙。每次還鑰匙的時候,還鑰匙的老師會找到最左邊的空的掛鈎,將鑰匙掛在這個掛鈎上。如果有多位老師還鑰匙,則他們按鑰匙編號從小到大的順序還。如果同一時刻既有老師還鑰匙又有老師取鑰匙,則老師們會先將鑰匙全還回去再取出。
今天開始的時候鑰匙是按編號從小到大的順序放在鑰匙盒里的。有 K位老師要上課,給出每位老師所需要的鑰匙、開始上課的時間和上課的時長,假設下課時間就是還鑰匙時間,請問最終鑰匙盒里面鑰匙的順序是怎樣的?
接下來 K行,每行三個整數 w, s, c,分別表示一位老師要使用的鑰匙編號、開始上課的時間和上課的時長。可能有多位老師使用同一把鑰匙,但是老師使用鑰匙的時間不會重疊。
保證輸入數據滿足輸入格式,你不用檢查數據合法性。
4 3 3
2 2 7
思路
1.整個過程與老師是沒有關系的,所以不需要考慮老師進來,復雜化題目。
2.開始想的是設定一個結構體teacher,即將一個老師的完整操作:鑰匙的編號、取出時間、還鑰匙時間作為一個整體。然后這個思路沒有繞出頭緒。
3.通過題目給出的樣例分析過程,可以看出來其實應該是將每個還鑰匙和取鑰匙的時刻看成一個整體進行操作。因為每個鑰匙都有一取一還的操作,所以總體的時間段是固定的,也就是2*K。然后通過分析每一個時刻,是做取鑰匙還是還鑰匙操作。取鑰匙就循環所有鑰匙,將取出鑰匙的位置至0;還鑰匙就循環所有鑰匙,在第一個鑰匙位置為0處存放鑰匙。
4.按照給出的輸入進行初始化(對於還鑰匙的時間,就是借鑰匙+上課時長),然后直接對2*k個時刻進行排序操作,排序操作就是按照題目中給出的“如果有多位老師還鑰匙,則他們按鑰匙編號從小到大的順序還。如果同一時刻既有老師還鑰匙又有老師取鑰匙,則老師們會先將鑰匙全還回去再取出”。之前很想不通的一個點就是考慮的因素不一樣,怎么排序呢,相互之間的因素會串線的吧?其實並不是,因為最后是以每個時刻為一個整體進行分析,無論是取是還,它都需要分析並得到這個時刻后的結果。所以直接對時刻(包含編號、時間、狀態)進行排序就好,之后的取還鑰匙過程按照這個順序進行就可以了。這樣就極大簡化了問題。
**一定不能夠把老師的一整套操作看成一個整體,這樣很難繞出來。一定要把每一個時刻單獨放出來,不需要想這樣就不能說明這是一個老師的操作了啊,這個題目不需要考慮老師是誰,只需要考慮這個時刻操作的是哪個鑰匙。而且老師使用鑰匙的時間不重合,所以一定能保證對這把鑰匙上一次是這個老師借,下一次就是這個老師還(即在這個老師借鑰匙和還鑰匙的區間里,不會有別人對這個鑰匙進行操作。所以不需要考慮別的情況,處理的狀態是取就循環所有鑰匙取,還就循環所有鑰匙還)。其實捋順了就很清晰
5.順便復習一下sort函數
#include <algorithm> //需要的頭文件 sort(begin, end, cmp); //其中begin為數組的第一個元素的指針,end為數組的最后一個元素的下一個位置的指針,cmp參數為排序准則,如果沒有的話,默認以非降序排序。
bool cmp(xx a1,xx a2){ //排序准則是return什么情況下為true
return ...;
}
題解
#include<iostream> #include<algorithm> using namespace std; struct condition{ int id;//使用的鑰匙編號 int time;//開始上課的時間/結束時間 int flag;//是借鑰匙還是還 }; bool cmp(condition k1,condition k2){//排序 if(k1.time!=k2.time){ return k1.time<k2.time; } else{ if(k1.flag!=k2.flag){//如果同一時間,先處理還鑰匙 return k1.flag<k2.flag; } else{//如果都是還鑰匙,先處理編號小的 return k1.id<k2.id; } } } int main(){ int N,K; scanf("%d %d",&N,&K); condition con[2*K]; for(int i=0;i<K;i++){ int w,s,c; scanf("%d %d %d",&w,&s,&c); con[i*2].id=w; con[i*2].time=s; con[i*2].flag=1; con[i*2+1].id=w; con[i*2+1].time=s+c; con[i*2+1].flag=-1; } sort(con,con+K*2,cmp); int keys[N]; for(int i=1;i<N+1;i++){ keys[i]=i; } //開始模擬 for(int i=0;i<2*K;i++){ //取鑰匙 if(con[i].flag==1){ for(int j=1;j<=N;j++){ if(keys[j]==con[i].id){ keys[j]=0; } } } //還鑰匙 else{ for(int j=1;j<=N;j++){ if(keys[j]==0){ keys[j]=con[i].id; break; } } } } for(int i=1;i<=N;i++){ if(i!=1) printf(" "); printf("%d",keys[i]); } return 0; }
這個題解參考了一個博主的解法(一時半會兒找不到出處鏈接了。。。)