From 85e30dc22fd8a511df2fa242e9f643dbeca9b9e0 Mon Sep 17 00:00:00 2001 From: Oliver Lew Date: Sat, 28 Apr 2018 21:18:42 +0800 Subject: [PATCH] update markdown file a1012-a1014 --- md/a1012.md | 16 ++++++----- md/a1013.md | 2 +- md/a1014.md | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 86 insertions(+), 8 deletions(-) diff --git a/md/a1012.md b/md/a1012.md index e5a218e..48da2d8 100644 --- a/md/a1012.md +++ b/md/a1012.md @@ -51,16 +51,20 @@ 我的方法是在读取学生成绩的时候顺便记录0~100分各有多少人,然后根据得分人数计算排名。举个例子: -- 如果100分有1人,99分有2人,98分有3人,97分有4人。那么得100分的排名是1,得99分的排名是2(并列),98分的排名是4(并列),97分的排名是7(并列)。 +- 如果100分有1人,99分有2人,98分有3人,97分有4人。 -规律是什么?如果分数从高到低是a1,a2,a3,...ai,...,那么 +那么 -- a[i]的名次 = a[i-1]的名次 + a[i-1]的人数 -- a[1]的名次 = 1 +- 得100分的排名是1,得99分的排名是2(并列),98分的排名是4(并列),97分的排名是7(并列)。 -这其实是递归定义,如果定义一个不存在的高分a[0]人数=1(比如101分)(代码中一开始的初始化就是做这个),那么 +规律是什么?如果学生获得的分数分别有a1>a2>a3>...>ai>...,那么 -- **a[i]的名次 = a[0]~a[i-1]的人数总和**,(i>0) +- 分数a[i]的名次 = 分数a[i-1]的名次 + 分数a[i-1]的人数 +- 分数a[1]的名次 = 1 + +这其实是递归定义,如果定义一个不存在的高分a0(比如101分)人数=1(代码中一开始的初始化就是做这个),那么上面的关系就简化成了 + +- **分数a[i]的名次 = a[0]~a[i-1]的人数总和**,(i>0) 可以验证一下:97分的排名=98~101分人数总和=3+2+1+1=7 diff --git a/md/a1013.md b/md/a1013.md index c8d1d9e..be8cd9c 100644 --- a/md/a1013.md +++ b/md/a1013.md @@ -171,4 +171,4 @@ int main() //} //} -``` +``` \ No newline at end of file diff --git a/md/a1014.md b/md/a1014.md index 1aa4481..c7983fc 100644 --- a/md/a1014.md +++ b/md/a1014.md @@ -36,6 +36,80 @@ ## 思路 +### 题意解读: + +银行有N个窗口, 每个窗口允许排M个顾客. 一大早8点所有顾客商量好蜂拥而入, +那么情况有两种: 1, 顾客全部能排在队伍里; 2, 顾客人数太多, 有人排在外面, +要等前面的顾客完成离开, 再进入列列. + +**注意点**: + +- 时间截止的标准是: 进入列列不晚于下午5点即可. 也就是说以进入列列时间为标准, + 中间用多长时间都没问题. 这个点包括我很多人肯定第一感觉是理解错的. + +### 代码结构 + +解读题目时提到可以存在两种情况, 我将这两种情况合并了一下: + +- 顾客一共有K个, 如果`K<=M*N`, 那么我用下面这图表示人次的流动情况(E表示入列, D表示 +出列, -表示此时无此操作): + + ``` + 时间顺序或者操作顺序--> + 出列: -----------------DDD...(K*D)...DDD + 入列: EEE...(K*E)...EEE----------------- + ``` + + 即表示一起进行K次入列, 然后一起进行K次出列, 就完成了. + +- 如果`K>M*N`, 那么其中有一段时间会交替有人出列/入列, 表示起来就是: + + ``` + 时间顺序或者操作顺序--> + 出列: ----(M*N)-----DDDDDD...(K*D)...DDD + 入列: EEE...(K*E)...EEEEEE----(M*N)----- + ``` + + 这表示前M*N次只有入列, 中间有顾客出列, 有顾客入列, 最后M*N次只有出列. + +总结这两种情况, 都是前K次是入列, 后K次是出列, 只需再计算出总的操作次数(出入记为 +一次)即可, 其实就是`max(2*K, M*N+K)`. + +这样代码结构就是 + +``` +循环max(2*K, M*N+K)次: + 如果是后K次: + 出列 + 如果是前K次: + 入列 +``` + +### 计时方法 + +数据结构: + +- 用一个数组(长度至少为K+1, 后面解释)先记录每个顾客的所需时间. 后面操作将这个时间 + 更新为顾客入列时间. + + 时间为距离早8点的分钟数. + + 如实按顾客编号(即从1开始)记录, 角标为0的元素保持为0. + +- 用N个队列模拟相关过程, 记录内容为顾客标号, 但是队列长度至少为M+1(后面解释) + +操作主要在入列时(因为入列时间很重要) + +入列时: + +- 找到长度最短的队列 +- 找到前面一个人的(包括标号0)对应时间 +- 将将要入列的人的时间加上上述时间, 即得到了此人的入列时间 + +出列时: + +- 只需找到所有队列队首中时间最早的对其出列即可 + ## 代码 [最新代码@github](https://github.com/OliverLew/PAT/blob/master/PATAdvanced/1014.c),欢迎交流 @@ -110,4 +184,4 @@ int main() return 0; } -``` +``` \ No newline at end of file