关于新BANK和函数调用关系

本文最后更新于:2023年7月8日 上午

关于新BANK和函数调用关系

$\mathscr{Author:CoolWind}$

1、新BANK

这破银行就活该倒闭!!!!(震声)

​ 本题的要点在于,不要去思考正常的银行应该如何运行,只需要去根据题干一步一步的进行下去即可。

​ 首先我们来分析题干。

新bank题干

​ 在本段题目中我们可以了解到以下几点:

  • 3$\leqslant$窗口数量$\leqslant$5,且起始窗口数量为3。

  • 窗口平均排队人数$\geqslant$7窗口增加,一直增加窗口数量到平均排队人数$\lt$7。

  • 窗口平均排队人数$\leqslant$7窗口减少,一直减少窗口数量到平均排队人数$\gt$7。

  • 客户在每个时间周期开始的时刻一同到来,没有来的先后顺序,但有接受服务的先后顺序。可以理解为在银行外已经排好队之后一同进入银行接受服务。

  • 当队列人数发生变动的时刻进行窗口增加、减少的判断。

    人数变动的时刻包括:

    • 每个时间周期开始的时候队列人数的增加。
    • 队列中的人前往窗口接受服务时人数的减少。
  • 用户的业务时长有1周期、2周期、3周期三种。

​ 以上就是我们能从题干中提取出来的有效信息。根据以上的信息,我们可以将本题的分为如下几步:

  1. 读取总时间周期长度以及每个时间周期内到达的人数。

  2. 读取每个周期内进入的所有用户以及用户的业务类别,用结构体储存每一个用户的编号、业务类别以及等待时间(初始等待时间为0),并将该用户压入队。

    注:一定要将所有用户都压入队之后再向下进行。

  3. 判断队列人数是否让窗口平均排队人数$\geqslant$7,若大于,一直增加窗口数量到平均排队人数$\lt$7。

  4. 将队头与空闲窗口数量相等数量的客户弹出,进入窗口进行业务办理,输出弹出用户的编号以及总等待时间。

  5. 判断队列人数是否让窗口平均排队人数$\leqslant$7,若小于,一直减少窗口数量到平均排队人数$\gt$7。

  6. 窗口业务处理时间-1。

  7. 队列中客户等待时间+1。

  8. 进行以上循环,到输入完毕(即没有新客户入队)。

  9. 由于没有新客户入队,所以窗口数量不会增加

  10. 循环4-7步直到队列空,结束进程。

​ 好了,思路搞清楚了,接下来就可以开始愉快地A题啦

​ 首先我们定义结构体数组作为储存队列方式:

1
2
3
4
5
6
struct queue
{
int num;
int workTime;
int waitTime;
} Queue[100010];

​ 根据步骤,我们要将用户的编号以及业务时间压入队中:

1
2
3
4
5
6
7
for (int k = 0; k < eachTurn; k++)
{
int workTime;
scanf("%d", &workTime);
Push(x, numInAll);
numInAll++;
}

​ 然后进行窗口数量增加的判断:

1
2
while (windowNumber * 7 <= queueLength && WindowNumber < 5)//注意窗口数量
windowNumber++;

​ 注意这里要令窗口数量小于5,不然容易加过头了

​ 本解采用数组的方式模拟窗口,其中窗口数组的下标表示窗口的编号,其内容表示该窗口正在处理的业务的时间。在将客户从队中弹出时的方法如下:

1
2
3
4
5
6
7
8
9
10
int Windows[6];
for (int p = 1; p <= windowNumber; p++)
{
if (Windows[p] == 0 && !queueEmpty())//窗口没有业务且队列不空
{
Windows[p] = FrontWorkTime();//队头客户的业务时间
printf("%d : %d\n", FrontNum(), FrontWaitTime());//输出
Pop();//弹出用户
}
}

​ 在弹出用户之后,我们理所当然的要进行窗口数量减少的判断:

1
2
while (WindowNumber * 7 > queueLength && WindowNumber > 3)//注意窗口数量
windowNumber--;

​ 之后,我们要减少窗口的业务时间、增加队列中客户等待时间:

1
2
3
4
5
6
7
8
9
10
for (int p = 1; p <= 5; p++)//注意每个窗口都要减少,而不是仅在windowNumber范围内
{
if (Windows[p] != 0)
Windows[p]--;
}

for (int p = front; p <= rear; p++)//遍历队列
{
Queue[p].WaitTime++;
}

​ 这里有一个魔鬼细节

​ 由于本解使用数组来对窗口的业务时间进行储存,在额外窗口的问题上可能出现如下问题:

​ 当4窗口已经办理完业务但5窗口业务仍未办理完,此时窗口会出现冗余。因为线性表的加持,导致本解中4窗口与5窗口并非两个独立且平行的窗口,而是具有先后关系的窗口,即5窗口开启的条件是4窗口开启。但是在实际情况中,两窗口为独立平行窗口。因此,为了避免这种情况,在每次判断完减少窗口业务时间之后,如果5窗口仍在办理业务而4窗口未办理业务,我们需要无情的将5窗口的客户赶到4窗口进行办理:

1
2
3
4
5
if(extraWindowsNum!=0&&Windows[4]==0&&Windows[5]!=0)
{
Windows[4]=Windows[5];
Windows[5]=0;
}

​ 在队列不再新增客户的时候,与以上内容相同,只是缺少了增加窗口这一环节。

​ 接下来给大家放出全部代码

2、函数调用关系

千万不要做完bank来做这个!千万不要画出树状图!不然人就傻了!(大佬除外QwQ)

​ 根据国际惯例,先看题干:

函数调用关系题干

​ 不难看出,这道题要考的就是栈。但是本题的难点不在于栈,而在于如何储存函数的调用信息

​ 这里我的思路是运用如下一个结构体的二维数组来储存函数调用信息:

1
2
3
4
5
struct storage
{
char name[25];//储存函数名称
int len;//储存函数调用的函数个数,只在主函数中使用,即第0位
}store[110][15];

​ 图形化表现为:

储存方式

​ 从题目的输入中我们可以知道8代表着入栈,0代表着出栈。接下来我们从入栈、出栈两个方面分别进行剖析。

​ 入栈:将函数名压入栈,并且在二维数组中储存函数名。

1
2
3
4
5
6
7
if(op==8)
{
scanf(" %s",s);//注意跳过空格
Push(s);//入栈
if(!findNameInStorage())
copyNameInStorage();
}

​ 出栈:弹出栈顶的函数,并且将其扔到相应的主函数的调用储存中。

​ 我们可以发现,被调用函数的主函数为栈顶函数的下一位函数。图形化表示为:

函数栈

1
2
3
4
5
6
7
8
9
10
11
if(op==0)
{
int flag = 0;
flag=findMainFunction();//在储存中找到该被调用函数的主函数,并记录其位置
int flag2=0;
if(findSonFunction(flag))//如果在对应主函数下找到被调用函数
flag2=1;
if(flag2==0)//未找到则将其加入该主函数对应的调用
strcpy(store[flag][++store[flag][0].len].s, stack[top].s);
Pop();
}

​ 重复以上步骤直至栈为空。

​ 最后遍历储存,并按照题干中要求进行输出。注意:调用函数数量为0的函数不需要输出

​ P.S.

​ 在以上步骤中,对比字符串是否相等可以使用!strcmp(a,b)表示a,b两个字符串相等,因为strcmp函数在两个字符串相等时会返回0。

​ 最后放上本题全部代码供大家参考。

以上就是鼠鼠对这两道题的思路!最后祝大家门门满绩,人人保研!


关于新BANK和函数调用关系
http://cool-wind.top/2023/04/24/关于新BANK和函数调用关系/
作者
CoolWind
发布于
2023年4月24日
许可协议