**
公共钥匙盒
**
[问题描述]
有一个学校的老师共用N个教室,按照规定,所有的钥匙都必须放在公共钥匙盒里,老师不能带钥匙回家。每次老师上课前,都从公共钥匙盒里找到自己上课的教室的钥匙去开门,上完课后,再将钥匙放回到钥匙盒中。
钥匙盒一共有N个挂钩,从左到右排成一排,用来挂N个教室的钥匙。一串钥匙没有固定的悬挂位置,但钥匙上有标识,所以老师们不会弄混钥匙。
每次取钥匙的时候,老师们都会找到自己所需要的钥匙将其取走,而不会移动其他钥匙。每次还钥匙的时候,还钥匙的老师会找到最左边的空的挂钩,将钥匙挂在这个挂钩上。如果有多位老师还钥匙,则他们按钥匙编号从小到大的顺序还。如果同一时刻既有老师还钥匙又有老师取钥匙,则老师们会先将钥匙全还回去再取出。
今天开始的时候钥匙是按编号从小到大的顺序放在钥匙盒里的。有K位老师要上课,给出每位老师所需要的钥匙、开始上课的时间和上课的时长,假设下课时间就是还钥匙时间,请问最终钥匙盒里面钥匙的顺序是怎样的?
[基本要求]
输入格式
输入的第一行包含两个整数N, K。
接下来K行,每行三个整数w, s, c,分别表示一位老师要使用的钥匙编号、开始上课的时间和上课的时长。可能有多位老师使用同一把钥匙,但是老师使用钥匙的时间不会重叠。
保证输入数据满足输入格式,你不用检查数据合法性。
输出格式
输出一行,包含N个整数,相邻整数间用一个空格分隔,依次表示每个挂钩上挂的钥匙编号。
样例输入
5 2
4 3 3
2 2 7
样例输出
1 4 3 2 5
样例说明
第一位老师从时刻3开始使用4号教室的钥匙,使用3单位时间,所以在时刻6还钥匙。第二位老师从时刻2开始使用钥匙,使用7单位时间,所以在时刻9还钥匙。
每个关键时刻后的钥匙状态如下(X表示空):
时刻2后为1X345;
时刻3后为1X3X5;
时刻6后为143X5;
时刻9后为14325。
要求:
(1)要求从文本文件中输入;
(2)根据时间进程,将取走钥匙和归还钥匙分别视为事件,放入队列中,然后通过每个事件的先后发生对钥匙盒的状态进行变更;
算法设计思想
1.利用队列存储钥匙编号,线性表存储老师的信息:老师要取的钥匙编号,还有取钥匙和还钥匙的时间。
2.Find_Time ( LinkQueue &Q, Linklist &L )
函数里设置循环,从最早取钥匙时间开始循环直到最迟归还钥匙时间,循环的变量为i,将i视为时刻,循环传入GT_keys ( LinkQueue &Q , Linklist &L , int i )中。
- GT_keys()函数执行还钥匙或取钥匙操作。
其具体算法思想为:
(1) 开始遍历存储老师信息的线性表
(2) 若有老师的还钥匙时间为i,且已拿到钥匙(if_key=1),则执行还钥匙操作:遍历队列,寻找第一个为0的钥匙编号值,并为它赋为这个老师要还的钥匙编号;
(3) 若有老师的取钥匙时间为i,且未拿到钥匙(if_key=0),则执行取钥匙操作:从队列中寻找这个老师要拿的钥匙编号,若存在,则将队列中这个钥匙的编号置为0,表示被取走,同时线性表中老师的if_key置为1;
#include
<stdio.h>
#include <stdlib.h>
#include<iostream>
#include<fstream>
using namespace std;
int key_num=0 , t_num=0 ;//存储钥匙数量和老师人数
int start=0 , finish=0;//最初的取钥匙时刻,最迟的还钥匙时刻
//队列存储钥匙信息
typedef struct QNode
{
int date;//存储钥匙号码,当钥匙被取走时,置为0
struct QNode *next;
}QNode , *QueuePtr;
//存储老师所用的钥匙和开始时间及结束时间
typedef struct LNode
{
int key;
int start , finish;
int if_key;//0为老师未拿到钥匙,1为拿到
struct LNode *next;
}LNode,*Linklist;
typedef struct
{
QueuePtr front;
QueuePtr rear;
}LinkQueue;
//输出事件队列状态
void show_List ( Linklist L )
{
LNode *p;
p = L->next;
int i=1;
while ( p )
{
if ( p->if_key==0 )
cout<< "第" << i
<< "位老师未拿到" << p->key << "号钥匙" <<endl;
else
{
cout<< "第" << i
<< "位老师于" << p->start << "时取到" << p->key << "号钥匙";
cout<< ",于" <<
p->finish << "时归还" <<endl;
}
p = p->next;
i++;
}
}
//利用图形显示钥匙盒实时状态
void image_key ( LinkQueue
&Q )
{
QNode *p;
if ( Q.front == Q.rear )
{
cout<<"钥匙盒为空!"<<endl;
exit(0);
}
p = Q.front->next;
cout<<"*****************************"<<endl;
cout<<"** ";
while( p!=Q.rear->next )
{
if ( p->date!=0 )//如果钥匙未被取走则输出
cout<< p->date << " **
";
else//钥匙被取走输出X
cout<< "X" <<
" **";
p = p->next;
}
cout<<endl<<"*****************************"<<endl;
}
//从文件里读取线性表信息
void createList ( Linklist
&L )
{
int
j;
LNode *p, *q;
L = (Linklist) malloc ( sizeof (LNode) );
L->next = NULL;
p = L;
ifstream read_in;
read_in.open( "text2.txt" );
if ( !read_in )
{
cout<< "文件读取失败!"
<<endl;
return;
}
read_in >> key_num;
read_in >> t_num;
while( !read_in.eof() )
{
q = (LNode *)malloc(sizeof(LNode));
read_in >>
q->key;
read_in >>
q->start;
read_in >>
j;
q->finish =
q->start+j;
p->next = q;
p = q;
p->if_key =
0;//表示钥匙未被取走
}
p->next = NULL;
p = L->next;
q = p->next;
read_in.close();
while( p )
{
if( p->start < q->start )
{
q = p;
}
p = p->next;
}
start = q->start;//最早取钥匙的时间
p = L->next;
q = p->next;
while( p )
{
if( p->finish > q->finish )
{
q = p;
}
p = p->next;
}
finish = q->finish;//最迟还钥匙的时间
}
//初始化钥匙信息,从1开始赋值
void InitQueue ( LinkQueue
&Q, int n )
{
Q.front = Q.rear = ( QueuePtr ) malloc (
sizeof (QNode));
if ( !Q.front )
exit(0);
Q.front->next = NULL;
QNode *p;
for ( int i=1; i<=n; i++ )
{
p = ( QueuePtr ) malloc ( sizeof (
QNode ) );
Q.rear->next = p;
p->date = i;
p->next = NULL;
Q.rear = p;
}
}
//销毁队列
void Destroy_Q ( LinkQueue
&Q )
{
while( Q.front )
{
Q.rear = Q.front->next;
free ( Q.front );
Q.front = Q.rear;
}
//cout<< "销毁成功" <<
endl;
}
//探空队列
int Empty_Q ( LinkQueue &Q
)
{
if (
!Q.front )
exit(0);
if ( Q.front == Q.rear )
return true;
else
return false;
}
//返回队列长度;
int Length_Q ( LinkQueue &Q
)
{
QNode *p;
int length = 0;
if ( !Q.front )
exit(0);
if ( Q.front == Q.rear )
return 0;
else
p = Q.front->next;
while(p)
{
length++;
p = p->next;
}
return ( length );
}
//根据时刻i执行取钥匙或还钥匙操作
void GT_keys ( LinkQueue &Q
, Linklist &L , int i )
{
LNode *p ;
QNode *q ;
if ( Q.front == Q.rear )
{
cout<<"此队列为空"<<endl;
return ;
}
q = Q.front->next;
p = L->next;
while ( p )
{
//还钥匙:若时刻i是某老师的还钥匙时刻,且已拿到钥匙
if ( p->finish==i &&
p->if_key==1 )
{
while ( q )//将第一个空位挂上这个老师要还的钥匙
{
if ( q->date == 0 )
{
q->date = p->key;
p->if_key = 1;
break;
}
q = q->next;
}
}
//取钥匙:若时刻i是某老师的取钥匙时刻,且未拿到钥匙
else if ( p->start==i &&
p->if_key==0 )
{
while ( q )//从队列里开始找这个老师想取的钥匙号码
{
if ( q->date == p->key )
{
q->date =0;
p->if_key = 1;
break;
}
q = q->next;
}
}
p = p->next;
}
}
//开始走时间,观察每个时刻所发生的变化
void Find_Time ( LinkQueue
&Q, Linklist &L )
{
int i;
if( Q.front == Q.rear )
{
cout<< "队列为空!"
<<endl;
}
for( i=1; i<=finish; i++ )
{
GT_keys ( Q, L, i );
cout<<endl<< "时刻"
<<i<<endl;
cout<< "事件队列的状态:"
<<endl;
show_List ( L );
cout<< "钥匙盒状态:"
<<endl;
image_key ( Q );
}
}
//输出最后钥匙盒的状态
void Look_All ( LinkQueue
&Q )
{
QNode *p;
if ( Q.front == Q.rear )
{
cout<< "队列为空!"
<<endl;
return ;
}
p = Q.front->next;
cout<<endl;
do
{
cout<< p->date <<"
";
p = p->next;
}while(p);
cout<<endl;
}
int main()
{
Linklist L;
createList( L );
LinkQueue Q;
InitQueue
( Q , key_num );
Find_Time (Q, L );
Look_All ( Q );
Destroy_Q (Q);
free(L);
return 0;
}
测试数据1:
5 7
1 1 14
3 3 12
1 15 12
2 7 20
3 18 12
4 21 19
5 30 9
显示钥匙盒的即时状态,以及事件队列的状态:
最终输出:12354