公共钥匙盒问题 (线性表 栈 队列)

**

公共钥匙盒

**
[问题描述]

有一个学校的老师共用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 )中。

  1. 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

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值