这里给出两种实现方式:
(1)使用map<time, multiset<key_id> >这种结构,存储用户输入的借还钥匙的序列(multiset允许相同元素存在,且自排序)。这里的思路是,将借还时间进行统一排序(原因A:time小的先处理;原因B:同一个key出现的次数是偶数,且先出现的一定是借,后出现的是还,且不允许嵌套,或者说一个借后面一定跟着对应的还。所以我可以这么排序),思路是:map内按照time为键进行排序,对于同一时刻,借还钥匙的id按照自小到大的顺序排列。
具体执行起来,由于map是排序的,所以只要顺序的获取map中的元素,然后对value进行操作即可。
value里面也是排过序的,但是由于还钥匙要在借之前,而value里面的序列是把借还的id进行了一个总排序,我们无法分成两段,第一段是按序的还钥匙的id,第二段是借钥匙的id(借钥匙不需要排序)。所以,我们只好进行两次遍历,第一次只处理要还的钥匙,然后将这个id从value中删掉,同时更新这个钥匙的status;第二次只处理借钥匙,然后更新钥匙的status(删除不删除都无所谓)。
这里表示钥匙状态的是一个数组keyStatus,下表对应钥匙id-1,状态只有两个值,0和1,1表示待还,0表示已还或者没有被借出。借还钥匙,都要更新该钥匙对应的状态。
#include<iostream>
#include<stdio.h>
#include <set>
#include <map>
#include <stdlib.h>
using namespace std;
typedef pair<int, multiset<int> > PAIR;
int main()
{
int Num_yaoshi,k_teachernum;
cin>>Num_yaoshi>>k_teachernum;
// Num_yaoshi=5;k_teachernum=7;
int *yaoshi_pailie =new int[Num_yaoshi], *keyStatus=new int[Num_yaoshi];
//初始化钥匙盒,以及每个钥匙的状态
for(int i=0;i<=Num_yaoshi-1;i++)
{
yaoshi_pailie[i]=i+1;
keyStatus[i]=0;//1 means the key has been borrowed
}
bool flag=false;
int *yaoshibianhao=new int[k_teachernum],*starttime=new int[k_teachernum],
*timelong=new int[k_teachernum],*endtime=new int[k_teachernum];
map<int, multiset<int> > sortedList;
map<int, multiset<int> >::iterator it;
multiset<int> tmpset;
multiset<int>::iterator setit;
//获取输入,并进行转换,然后行程键值对,放到map中
for(int i=0;i<=k_teachernum-1;i++)
{
cin>>yaoshibianhao[i]>>starttime[i]>>timelong[i];
endtime[i]=starttime[i]+timelong[i];
//add the yaoshibianhao[i] into map according to the starttime,按照借的时间把keyid放进去
it=sortedList.find(starttime[i]);
if(it==sortedList.end()){//not in the map
//add the PAIR<starttime[i],multiset<yaoshibianhao[i]>> into map
tmpset.clear();
}
else{// the time has appeared in the map, so add the yaoshibianhao[i] into the tmpset
tmpset=it->second;
sortedList.erase(it);
}
tmpset.insert(yaoshibianhao[i]);
sortedList.insert(make_pair(starttime[i],tmpset));
tmpset.clear();
//add the yaoshibianhao[i] into map according to the endtime,按照还的时间将keyid放到map中
it=sortedList.find(endtime[i]);
if(it==sortedList.end()){//not in the map
//add the PAIR<starttime[i],multiset<yaoshibianhao[i]>> into map
tmpset.clear();
}
else{// the time has appeared in the map, so add the yaoshibianhao[i] into the tmpset
tmpset=it->second;
sortedList.erase(it);
}
tmpset.insert(yaoshibianhao[i]);
sortedList.insert(make_pair(endtime[i],tmpset));
tmpset.clear();
}
//test the input,测试用户的输入能否正常存储到map中
/*
it = sortedList.begin();
while(it != sortedList.end())
{
cout<<it->first<<": "<<it->second.size()<<endl;
it ++;
}
*/
//对map进行遍历,处理借还钥匙
for(it = sortedList.begin();it != sortedList.end();)
{
tmpset.clear();
tmpset=it->second;//
cout<<"处理时间:"<<it->first<<", 共有:"<<tmpset.size()<<endl;
int j=0;
// 先处理还钥匙
for(setit =tmpset.begin(); setit!=tmpset.end();){
//find the keys to be returned and return them
flag=false;
//printf("%d",*setit);
if(keyStatus[(*setit)-1]==1) {//如果该key的状态为1,表示待还,
cout<<"归还key_ "<<*setit;
keyStatus[(*setit)-1]=0;//更新钥匙状态
for(int i=0;i<Num_yaoshi;i++){//这个可以使用一个set来代替,就不用循环了 ,按照顺序,找到钥匙盒中的第一个空位置
if(yaoshi_pailie[i]==0) {//
cout<<", 放到位置"<<i+1<<endl;
yaoshi_pailie[i]=(*setit);//把钥匙放到空位置
tmpset.erase(setit++);//从value中删掉这个key
flag=true;
break;//后面不再需要找空位置了
}
}
if(flag==false) setit++;
continue;
}
setit++;
}
//borrow key,借钥匙
if(tmpset.size()>0){//防止这一时刻只有还钥匙的操作,则还过钥匙后tmpset为空,所以要判断size
for( setit = tmpset.begin();setit!=tmpset.end();)
{
cout<<"id= "<<(*setit)<<" ";
keyStatus[(*setit)-1]=1;//更新钥匙状态
for(int i=0;i<Num_yaoshi;i++){//这个可以使用一个set来代替,就不用循环了 ,找到钥匙盒中这个钥匙的位置
if(yaoshi_pailie[i]==(*setit)) {
yaoshi_pailie[i]=0;//钥匙盒中对应的位置置空
//tmpset.erase(setit++);
flag=true;
break;
}
}
setit++;//这个很重要
}
tmpset.clear();
}
it ++;
}
//输出结果
for(int i=0;i<=Num_yaoshi-1;i++)
cout<<yaoshi_pailie[i]<<" ";
//删除数组
yaoshi_pailie=NULL;
delete [] yaoshi_pailie;
delete [] keyStatus;
delete [] yaoshibianhao;
delete [] starttime;
delete [] timelong;
delete [] endtime;
return 0;
}
(2)使用一大堆的set来处理钥匙盒的问题,由于set是自排序的,所以这里弄了几个set来表示已经借的钥匙的集合,本时刻要还的钥匙的集合,空位置的集合。然后按照时刻从1到max_time进行遍历,对于每一个时刻,先找本时刻要还的钥匙的集合,然后还钥匙,然后再借钥匙。
#include <iostream>
#include <string>
#include <stdio.h>
#include <set>
using namespace std;
int main(){
int N,K,MAX_TIME=0;
cin>>N>>K;
int *borrowTime=new int[K],*backTime=new int[K],*keyID=new int[K], *keys=new int[N];
set<int> emptyPos;//used to record the postion that is empty, items in set are sorted by default
set<int> borrowedKeys;//used to record the keys not returned
set<int> returningKeys;//used to record the keys to returned at current time
set<int> borrowingKeys;
for(int i=0;i<N;i++){
keys[i]=i+1;//initializing the kyes postion at the beginning
}
//get the status of the keys of the day
for(int i=0;i<K;i++){
scanf("%d %d %d\n",&keyID[i],&borrowTime[i],&backTime[i]);//>>endl;
backTime[i]=backTime[i]+borrowTime[i];
if(backTime[i]>MAX_TIME) MAX_TIME=backTime[i];
}
for(int i=1;i<=MAX_TIME;i++){
int backAmount=0,borrowAcount=0;
for(int j=0;j<K;j++){
if(backTime[j]==i){//the key will be back at this period
returningKeys.insert(keyID[j]);//put all the keys will be back at this period into the set
borrowedKeys.erase(keyID[j]);
backAmount++;
}
if(borrowTime[j]==i){//get the keys being borrowed at this period
borrowingKeys.insert(keyID[j]);
borrowedKeys.insert(keyID[j]);
borrowAcount++;
}
}
//put the sorted keys into the position specified by the sorted emptyPos
if(backAmount>0){
for(int k=0;k<backAmount;k++){
int key=*returningKeys.begin();
int pos =*emptyPos.begin();
keys[pos]=key;
returningKeys.erase(key);
emptyPos.erase(pos);
}
}
//remove the borrowing keys at this period
if(borrowAcount>0){
for(int k=0;k<borrowAcount;k++){// can be replaced with map
for(int k1=0;k1<N;k1++){
int keyid=*borrowingKeys.begin();
if(keys[k1]==keyid){
emptyPos.insert(k1);
borrowingKeys.erase(keyid);
keys[k1]=0;
break;
}
}
}
}
borrowingKeys.clear();
returningKeys.clear();
}
for(int s1=0;s1<N;s1++){
printf("%d ",keys[s1]);
}
delete [] borrowTime;
delete [] backTime;
delete [] keys;
delete [] keyID;
return 0;
}?