#P2367. 第1题-打卡
          
                        
                                    
                      
        
              - 
          
          
                      1000ms
            
          
                      Tried: 530
            Accepted: 101
            Difficulty: 5
            
          
          
          
                       所属公司 : 
                              华为
                                
            
                        
              时间 :2023年8月30日-国内
                              
                      
          
 
- 
                        算法标签>模拟          
 
第1题-打卡
题目描述
某高科技公司为员工提供智慧打卡系统,记录员工每日的进出门禁时间。为计算员工的实际工作时长,考虑以下规则:离岗时间不超过 15 分钟的,不扣除工作时长;午休时间为 12:00 至 14:00,此时间段内不算工作时长;晚饭时间为 18:00 至 19:30,此时间段内也不算工作时长。
输入包括四行:第一行是员工当天进门禁的次数 ( n );第二行是员工当天所有的入门禁时间,以空格分隔(格式为 HH:MM);第三行是员工当天出门禁的次数 ( m );第四行是员工当天所有的出门禁时间,以空格分隔(格式为 HH:MM)。输出为员工当天的工作时长(单位:分钟)。
思路: 模拟
若离岗时间不超过15min,那么直接可以将出门禁时间改为下次入门禁时间。对于午休时间和晚饭时间,可以将入门禁时间改为午休和晚饭的结束,出门禁时间改为午休和晚饭的开始。处理后可能会存在单次打卡出门禁时间在入门禁时间之前,直接将本次工作时间置零即可。然后计算单次工作时间。
题解
我们需要计算员工的工作时长,具体考虑以下几点:
- 
输入与数据结构:
- 我们首先读取员工当天的入门禁和出门禁时间。为了方便计算,使用一个 
pair<int, int>的结构来存储时间(小时和分钟)。 
 - 我们首先读取员工当天的入门禁和出门禁时间。为了方便计算,使用一个 
 - 
离岗时间的处理:
- 如果员工的离岗时间不超过 15 分钟,可以认为该段时间内不算离岗,因此可以将该次出门禁时间替换为下次入门禁时间。
 
 - 
午休和晚饭时间的处理:
- 午休时间为 12:00 到 14:00,晚饭时间为 18:00 到 19:30。在计算工作时长时,如果入门禁时间落在午休时间或晚饭时间内,需要调整入门禁和出门禁的时间:
- 入门禁时间调整为午休结束或晚饭结束的时间。
 - 出门禁时间调整为午休开始或晚饭开始的时间。
 
 
 - 午休时间为 12:00 到 14:00,晚饭时间为 18:00 到 19:30。在计算工作时长时,如果入门禁时间落在午休时间或晚饭时间内,需要调整入门禁和出门禁的时间:
 - 
计算有效工作时长:
- 对于每一对入门禁和出门禁时间,计算其对应的工作时长,并累加。如果出门禁时间在入门禁时间之前,则该段工作时间为 0。
 
 
代码
C++
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pb push_back
#define mr make_pair
#define fi first
#define se second
typedef pair<int, int> Pii;
// 计算两次打卡时间的差值(返回有效工作时长)
int cal(Pii p1, Pii p2) {
    if (p2 <= p1) return 0; // 如果出门禁时间在入门禁时间之前,则置零
    return (p2.fi - p1.fi - 1) * 60 + (60 - p1.se + p2.se);
}
int main() {
    int n, mm, h, m;
    cin >> n; // 读取入门禁次数
    vector<Pii> s, e; // s存储入门禁时间,e存储出门禁时间
    
    // 读取入门禁时间
    for (int i = 0; i < n; i++) {
        scanf("%d:%d", &h, &m);
        s.pb(mr(h, m)); // 将时间存储为pair
    }
    
    cin >> mm; // 读取出门禁次数
    int ans = 0; // 初始化工作时长
    for (int i = 0; i < mm; i++) {
        scanf("%d:%d", &h, &m);
        if (i != mm - 1) {
            // 如果当前出门禁时间与下一个入门禁时间的差值小于等于15分钟
            if (cal(mr(h, m), s[i + 1]) <= 15) {
                e.pb(s[i + 1]); // 将出门禁时间替换为下次入门禁时间
                continue;
            }
        }
        e.pb(mr(h, m)); // 存储当前出门禁时间
    }
    
    // 处理午休和晚饭的时间段
    for (int i = 0; i < n; i++) {
        if (s[i].fi < 14 && s[i].fi >= 12) s[i].fi = 14, s[i].se = 0; // 入门禁时间在午休期间,调整为14:00
        if (s[i].fi == 18 || (s[i].fi == 19 && s[i].se <= 30)) s[i].fi = 19, s[i].se = 30; // 入门禁时间在晚饭期间,调整为19:30
    }
    
    for (int i = 0; i < mm; i++) {
        if (e[i].fi < 14 && e[i].fi >= 12) e[i].fi = 12, e[i].se = 0; // 出门禁时间在午休期间,调整为12:00
        if (e[i].fi == 18 || (e[i].fi == 19 && e[i].se <= 30)) e[i].fi = 18, e[i].se = 0; // 出门禁时间在晚饭期间,调整为18:00
        
        // 计算有效工作时长并累加
        ans += cal(s[i], e[i]);
    }
    
    cout << ans << endl; // 输出总工作时长
    return 0;
}
java
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Main {
    // 定义一个Pair类,用于存储时间的小时和分钟
    static class Pair {
        int fi, se; // fi代表小时,se代表分钟
        Pair(int fi, int se) {
            this.fi = fi; // 初始化小时
            this.se = se; // 初始化分钟
        }
        // 比较当前时间与其他时间,判断是否小于等于
        boolean lessThanOrEqualTo(Pair other) {
            return this.fi < other.fi || (this.fi == other.fi && this.se <= other.se);
        }
    }
    // 计算两次打卡时间的差值(返回有效工作时长)
    static int cal(Pair p1, Pair p2) {
        if (p2.lessThanOrEqualTo(p1)) return 0; // 如果出门禁时间在入门禁时间之前,则置零
        // 计算工作时长
        return (p2.fi - p1.fi - 1) * 60 + (60 - p1.se + p2.se);
    }
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in); // 创建扫描器以读取输入
        int n = sc.nextInt(); // 读取入门禁次数
        List<Pair> s = new ArrayList<>(); // 存储入门禁时间
        List<Pair> e = new ArrayList<>(); // 存储出门禁时间
        // 读取入门禁时间
        for (int i = 0; i < n; i++) {
            String[] str = sc.next().split(":"); // 按照':'分割时间字符串
            int h = Integer.parseInt(str[0]); // 解析小时
            int m = Integer.parseInt(str[1]); // 解析分钟
            s.add(new Pair(h, m)); // 将时间存储为Pair对象
        }
        int mm = sc.nextInt(); // 读取出门禁次数
        int ans = 0; // 初始化工作时长
        // 读取出门禁时间
        for (int i = 0; i < mm; i++) {
            String[] str = sc.next().split(":"); // 按照':'分割时间字符串
            int h = Integer.parseInt(str[0]); // 解析小时
            int m = Integer.parseInt(str[1]); // 解析分钟
            
            // 如果不是最后一次出门禁
            if (i != mm - 1) {
                // 若离岗时间不超过15分钟,则将出门禁时间改为下次入门禁时间
                if (cal(new Pair(h, m), s.get(i + 1)) <= 15) {
                    e.add(new Pair(s.get(i + 1).fi, s.get(i + 1).se)); // 使用下一个入门禁时间
                    continue; // 跳过当前循环
                }
            }
            e.add(new Pair(h, m)); // 存储当前出门禁时间
        }
        // 处理午休和晚饭的时间段
        for (int i = 0; i < n; i++) {
            if (s.get(i).fi < 14 && s.get(i).fi >= 12) { // 如果入门禁时间在午休期间
                s.get(i).fi = 14; // 将入门禁时间调整为14:00
                s.get(i).se = 0; // 分钟部分设置为0
            }
            if (s.get(i).fi == 18 || (s.get(i).fi == 19 && s.get(i).se <= 30)) { 
                // 如果入门禁时间在晚饭期间
                s.get(i).fi = 19; // 将入门禁时间调整为19:30
                s.get(i).se = 30;
            } 
        }
        
        // 处理出门禁时间
        for (int i = 0; i < mm; i++) {
            if (e.get(i).fi < 14 && e.get(i).fi >= 12) { // 如果出门禁时间在午休期间
                e.get(i).fi = 12; // 将出门禁时间调整为12:00
                e.get(i).se = 0; // 分钟部分设置为0
            }
            if (e.get(i).fi == 18 || (e.get(i).fi == 19 && e.get(i).se <= 30)) { 
                // 如果出门禁时间在晚饭期间
                e.get(i).fi = 18; // 将出门禁时间调整为18:00
                e.get(i).se = 0; // 分钟部分设置为0
            }
            ans += cal(s.get(i), e.get(i)); // 计算有效工作时长并累加
        }
        System.out.println(ans); // 输出总工作时长
    }
}
python
def cal(p1, p2):
    # 计算两次打卡时间的差值(返回有效工作时长)
    if p2 <= p1:  # 处理后可能会存在单次打卡出门禁时间在入门禁时间之前,直接置零
        return 0
    # 计算工作时长,考虑小时和分钟的差值
    return (p2[0] - p1[0] - 1) * 60 + (60 - p1[1] + p2[1])
# 读取入门禁次数
n = int(input())
s = []  # 存储入门禁时间
str = list(input().split())  # 读取入门禁时间字符串并分割
for i in range(n):
    h, m = map(int, str[i].split(":"))  # 将HH:MM格式的时间解析为小时和分钟
    s.append((h, m))  # 存储为元组 (小时, 分钟)
# 读取出门禁次数
mm = int(input())
e = []  # 存储出门禁时间
str = list(input().split())  # 读取出门禁时间字符串并分割
for i in range(mm):
    h, m = map(int, str[i].split(":"))  # 将HH:MM格式的时间解析为小时和分钟
    # 如果不是最后一次出门禁
    if i != mm - 1:
        # 若离岗时间不超过15分钟,则将出门禁时间替换为下次入门禁时间
        if cal((h, m), s[i + 1]) <= 15:
            e.append(s[i + 1])  # 使用下一个入门禁时间
            continue  # 跳过当前循环
    e.append((h, m))  # 存储当前出门禁时间
# 处理午休和晚饭的时间段
for i in range(n):
    if 12 <= s[i][0] < 14:  # 如果入门禁时间在午休期间
        s[i] = (14, 0)  # 将入门禁时间调整为14:00
    if s[i][0] == 18 or (s[i][0] == 19 and s[i][1] <= 30):
        s[i] = (19, 30)  # 将入门禁时间调整为19:30
# 处理出门禁时间
for i in range(mm):
    if 12 <= e[i][0] < 14:  # 如果出门禁时间在午休期间
        e[i] = (12, 0)  # 将出门禁时间调整为12:00
    if e[i][0] == 18 or (e[i][0] == 19 and e[i][1] <= 30):
        e[i] = (18, 0)  # 将出门禁时间调整为18:00
# 计算总的工作时长
ans = 0
for i in range(mm):
    ans += cal(s[i], e[i])  # 累加每段工作时间
print(ans)  # 输出总工作时长
        题目描述
某高科技公司为员工提供智慧打卡系统,记录员工每日的进出门禁时间。为计算员工的实际工作时长,考虑以下规则:离岗时间不超过 15 分钟的,不扣除工作时长;午休时间为 12:00 至 14:00,此时间段内不算工作时长;晚饭时间为 18:00 至 19:30,此时间段内也不算工作时长。
输入描述
输入包括四行:第一行是员工当天进门禁的次数 ( n );第二行是员工当天所有的入门禁时间,以空格分隔(格式为 HH:MM);第三行是员工当天出门禁的次数 ( m );第四行是员工当天所有的出门禁时间,以空格分隔(格式为 HH:MM)。
输出描述
输出为员工当天的工作时长(单位:分钟)。
样例 输入
10
02:19 06:39 07:52 14:42 16:53 18:01 19:12 20:54 22:31 23:27 
10
02:45 07:17 13:37 15:52 16:56 19:10 19:21 22:15 22:34 23:38
输出
480