涉及到时间计算的题目,往往让大家感到头疼,情况太多,根本无重下手。例如:请计算12:05:24和13:04:23这两个时刻相差了多少时间。以前我的想法也十分的笨拙,下面就来看看我原来的思路。
简单来讲就是计算每个时间单位离“进位”(秒和分是60,时是24)还差多少个单位,再看从0到终点的那个单位差多少,再进行累加。这样一来还要分很多种小情况,特别容易遗漏情况,例如12:05:24和12:05:25,这样没有进位的结果需要特判,往往我调了半个小时还是错误的,也找不出反例来看到底是漏了哪种情况。这是一种暴力而且“丑陋”的思想,所以就不放代码上来了。
后来我又想到了模拟的方法,通过秒的增加来模拟电子时钟变化的过程,记录到达目标时刻的秒数,转换成小时数、分钟数和秒数。但这种方法耗时久,代码如下:
int t=0; //t来记录当前走过的秒数
while (h1!=h2&&m1!=m2&&s1!=s2) //走到目标时间终止模拟
{
s1++;
t++;
if (s1 >= 60) //秒超过60分加一
{
s1 -= 60;
m1++;
}
if (m1 >= 60) //分的“进位”
{
m1 -= 60;
h1++;
}
if (h1 >= 24) //如果“过了一天”,使小时保持在24以内才可能和目标相等
{
h1 -= 24;
}
}
/*
h为小时数
m为分钟数
s为秒钟数
*/
int h=t/3600;//除以分钟和秒钟的最大值,60*60
t%=3600;
int m=t/60;//除以秒钟的最大值
t/=60;
int s=t;
其实我们看到上面代码通过走过的秒数求出经过的小时数、分钟数、秒数的过程可以体会到一个和“分离整数的各个位”很相似的思想,其实我们就是在把一个十进制数(经过的秒数)转换成“小时进制数/分钟进制数”。于是衍生出了本文要着重介绍的最简单的方法:转换成数法
我们可以把用形如XX:XX:XX的时刻形式看作一个由三种不同进制的数组成的一个结构体,小时位是一个24进制数,分钟和秒钟是一个60进制数,而我们要做的就是把这这个时刻结构体转化成一个10进制的数,转化的方法很简单(受上面代码的启发),,就得到了一个数(十进制,可以看作是从00:00:00到当前时刻走过的秒的数)。我们把起始时刻和终止时刻转化成这个十进制数
后,经过的秒数
易求。在把两个时刻的“秒数差”dt按照上面代码的转换思路成对应进制的数就求出来了。短短几行代码就解决了这个困扰许久的问题。
下面为了体验这个方法的方便,解决一道实际问题吧。
A | Everyone Loves to Sleep |
A. Everyone Loves to Sleep
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
Vlad, like everyone else, loves to sleep very much.
Every day Vlad has to do nn things, each at a certain time. For each of these things, he has an alarm clock set, the ii-th of them is triggered on hihi hours mimi minutes every day (0≤hi<24,0≤mi<600≤hi<24,0≤mi<60). Vlad uses the 2424-hour time format, so after h=12,m=59h=12,m=59 comes h=13,m=0h=13,m=0 and after h=23,m=59h=23,m=59 comes h=0,m=0h=0,m=0.
This time Vlad went to bed at HH hours MM minutes (0≤H<24,0≤M<600≤H<24,0≤M<60) and asks you to answer: how much he will be able to sleep until the next alarm clock.
If any alarm clock rings at the time when he went to bed, then he will sleep for a period of time of length 00.
Input
The first line of input data contains an integer tt (1≤t≤1001≤t≤100) — the number of test cases in the test.
The first line of the case contains three integers nn, HH and MM (1≤n≤10,0≤H<24,0≤M<601≤n≤10,0≤H<24,0≤M<60) — the number of alarms and the time Vlad went to bed.
The following nn lines contain two numbers each hihi and mimi (0≤hi<24,0≤mi<600≤hi<24,0≤mi<60) — the time of the ii alarm. It is acceptable that two or more alarms will trigger at the same time.
Numbers describing time do not contain leading zeros.
Output
Output tt lines, each containing the answer to the corresponding test case. As an answer, output two numbers — the number of hours and minutes that Vlad will sleep, respectively. If any alarm clock rings at the time when he went to bed, the answer will be 0 0.
Example
input
3
1 6 13
8 0
3 6 0
12 30
14 45
6 0
2 23 35
20 15
10 30
output
1 47 0 0 10 55
当时做这个题用纯模拟调到结束也没找到错误,看看使用新方法后的AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
int main()
{
int t;
cin >> t;
while (t--)
{
int n, H, M;
cin >> n >> H >> M;
int mint = N;
int ot = 60 * H + M;
while (n--)
{
int h, m;
cin >> h >> m;
int nt = 60 * h + m;
int dt = nt - ot;
if (dt < 0)
dt += 24 * 60;
mint = min(dt, mint);
}
cout << mint / 60 << " " << mint - mint / 60 * 60 << endl;
}
return 0;
}