#P3098. 手机APP防沉迷系统(100分)
-
1000ms
Tried: 159
Accepted: 35
Difficulty: 6
所属公司 :
华为od
-
算法标签>模拟
手机APP防沉迷系统(100分)
题面描述
在智能手机的“App防沉迷系统”中,用户可以注册多个App的使用时段。系统有以下规则:
- 时段注册:用户可以在一天24小时内为每个App注册允许的使用时段。
- 时段冲突:一个时间段内只能使用一个App,不能同时使用多个App。
- 优先级处理:
- 每个App有一个优先级,数值越高优先级越高。
- 当高优先级的App注册时段与低优先级的App时段冲突时,系统会自动注销低优先级的App的时段。
- 如果两个App的优先级相同,后注册的App无法覆盖先注册的App。
- 多时段注册:一个App可以在一天内注册多个时段。
给定多个App的注册信息和一个查询时间点,要求输出该时间点正在使用的App名称。如果没有任何App在该时间点注册使用,则输出“NA”。
思路
为了实现上述规则,我们可以采用以下步骤:
- 时间转换:将时间格式“HH:MM”转换为分钟数,方便比较和处理。例如,“09:30”转换为570分钟。
- 时间线模拟:建立一个长度为1440(24小时×60分钟)的时间线数组,每个元素表示对应分钟使用的App及其优先级。
- 注册处理:
- 按照输入的注册顺序依次处理每个App的注册时段。
- 对于每个App的每一个注册时段,将该时段内的每一分钟进行检查:
- 如果该分钟尚未被其他App占用,则直接分配给当前App。
- 如果该分钟已经被其他App占用,则比较优先级:
- 如果当前App的优先级更高,覆盖原有的App。
- 如果优先级相同或更低,保持原有的App不变。
- 查询处理:将查询时间点转换为分钟数,查找时间线数组对应分钟的App名称。如果没有App占用该分钟,则输出“NA”。
这种方法通过时间线数组模拟一天的24小时,确保了时段冲突和优先级规则的正确处理。
cpp
#include <bits/stdc++.h>
using namespace std;
class Application {
public:
string appName; // 应用名称
int appPriority; // 应用优先级
int startMinute; // 开始时间(分钟)
int endMinute; // 结束时间(分钟)
Application(string name, int priority, int startTime, int endTime)
: appName(std::move(name)), appPriority(priority),
startMinute(startTime), endMinute(endTime) {};
};
int convertTime(string &timeStr) {
// 时间格式 HH:MM,小时和分钟都是两位,不足两位前面补0
stringstream ss(timeStr);
string hours;
getline(ss, hours, ':');
string minutes;
getline(ss, minutes, ':');
return stoi(hours) * 60 + stoi(minutes);
}
string getRegisteredApp(vector<Application> &apps, int queryTime) {
// 记录已注册的应用
vector<Application> registeredApps;
for (const auto &app : apps) {
// 起始时间 >= 结束时间,则注册失败
if (app.startMinute >= app.endMinute) continue;
// 记录被注销的应用的索引
vector<int> toBeDeletedIdxs;
bool cannotRegister = false;
// 比较正在注册的应用和已注册的所有应用
for (int j = 0; j < registeredApps.size(); j++) {
Application registeredApp = registeredApps[j];
// 两个应用的注册时间无冲突,则继续比较下一个已注册应用
if (registeredApp.startMinute >= app.endMinute || app.startMinute >= registeredApp.endMinute) {
continue;
}
// 如果有冲突,比较优先级
if (app.appPriority > registeredApp.appPriority) {
// 记录需要注销的已注册应用的索引
toBeDeletedIdxs.emplace_back(j);
} else {
// 当前应用优先级低或相等,无法注册,终止比较
cannotRegister = true;
}
}
if (cannotRegister) {
continue;
}
// 反向删除已记录的应用索引,避免索引变化
for (int j = toBeDeletedIdxs.size() - 1; j >= 0; j--) {
int deleteIdx = toBeDeletedIdxs[j];
registeredApps.erase(registeredApps.begin() + deleteIdx);
}
// 注册当前应用
registeredApps.emplace_back(app);
}
string result = "NA";
// 注册成功的应用时间段互不冲突,因此查询时间只会对应一个应用
for (const auto &app : registeredApps) {
if (queryTime >= app.startMinute && queryTime < app.endMinute) {
result = app.appName;
break;
}
}
return result;
}
int main() {
int numApps;
cin >> numApps;
// 需要注册的应用
vector<Application> apps;
for (int i = 0; i < numApps; i++) {
string name;
int priority;
string startTime;
string endTime;
cin >> name >> priority >> startTime >> endTime;
apps.emplace_back(name, priority, convertTime(startTime), convertTime(endTime));
}
// 需要查询的时间点
string queryTime;
cin >> queryTime;
cout << getRegisteredApp(apps, convertTime(queryTime)) << endl;
return 0;
}
python
class Application:
def __init__(self, app_name, app_priority, start_time, end_time):
self.app_name = app_name # 应用名称
self.app_priority = app_priority # 应用优先级
self.start_time = start_time # 开始时间(分钟)
self.end_time = end_time # 结束时间(分钟)
def convert(time_str):
# 时间格式 HH:MM,小时和分钟都是两位,不足两位前面补0
hours, minutes = map(int, time_str.split(":"))
return hours * 60 + minutes
# 输入获取
num_apps = int(input())
# 需要注册的应用
apps = []
for _ in range(num_apps):
app_name, app_priority, start_time, end_time = input().split(" ")
apps.append(Application(app_name, int(app_priority), convert(start_time), convert(end_time)))
# 需要查询的时间点
query_time = convert(input())
# 算法入口
def get_result():
registered_apps = []
for app in apps:
# 起始时间>=结束时间,则注册不上
if app.start_time >= app.end_time:
continue
# 记录已注册的应用中被注销的应用的位置
to_be_deleted_idx = []
cannot_register = False
# 比较正在注册的应用和它前面完成注册的所有已注册应用
for j in range(len(registered_apps)):
registered_app = registered_apps[j]
# 两个应用的注册时间无冲突,则继续和下一个已注册应用比较
if registered_app.start_time >= app.end_time or app.start_time >= registered_app.end_time:
continue
# 两个应用的注册时间有冲突,则比较优先级
if app.app_priority > registered_app.app_priority:
# 记录需要注销的已注册应用的索引
to_be_deleted_idx.append(j)
else:
# 当前应用的优先级低于或等于已注册应用的优先级,无法注册,终止比较
cannot_register = True
break
# 如果当前应用无法注册,则终止比较
if cannot_register:
continue
# idxs中索引是升序的,采用倒序删除
to_be_deleted_idx.reverse()
for idx in to_be_deleted_idx:
registered_apps.pop(idx)
registered_apps.append(app)
result = "NA"
# 注册成功的应用时间段互不冲突,因此查询时间只会对应一个应用
for registered_app in registered_apps:
if registered_app.start_time <= query_time < registered_app.end_time:
result = registered_app.app_name
break
return result
# 算法调用
print(get_result())
java
import java.util.ArrayList;
import java.util.Scanner;
public class Main {
static class Application {
String appName; // 应用名称
int appPriority; // 应用优先级
int startMinute; // 开始时间(分钟)
int endMinute; // 结束时间(分钟)
public Application(String name, int priority, int startTime, int endTime) {
this.appName = name;
this.appPriority = priority;
this.startMinute = startTime;
this.endMinute = endTime;
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int numApps = sc.nextInt();
// 需要注册的应用
ArrayList<Application> apps = new ArrayList<>();
for (int i = 0; i < numApps; i++) {
apps.add(new Application(sc.next(), sc.nextInt(), convert(sc.next()), convert(sc.next())));
}
// 需要查询的时间点
int queryTime = convert(sc.next());
System.out.println(getResult(apps, queryTime));
}
public static String getResult(ArrayList<Application> apps, int queryTime) {
// 记录已注册的应用
ArrayList<Application> registeredApps = new ArrayList<>();
outer:
for (Application app : apps) {
// 起始时间 >= 结束时间,则注册不上
if (app.startMinute >= app.endMinute) continue;
// 记录被注销的已注册应用的索引
ArrayList<Integer> toBeDeletedIdxs = new ArrayList<>();
// 比较正在注册的应用和它前面已注册的所有应用
for (int j = 0; j < registeredApps.size(); j++) {
Application registeredApp = registeredApps.get(j);
// 两个应用的注册时间无冲突,则继续比较下一个已注册应用
if (registeredApp.startMinute >= app.endMinute || app.startMinute >= registeredApp.endMinute) continue;
// 两个应用的注册时间有冲突,则比较优先级
if (app.appPriority > registeredApp.appPriority) {
// 记录需要注销的已注册应用的索引
toBeDeletedIdxs.add(j);
} else {
// 当前应用优先级低于或等于已注册应用的优先级,无法注册,终止比较
continue outer;
}
}
// 反向删除被记录的索引
for (int j = toBeDeletedIdxs.size() - 1; j >= 0; j--) {
int deleteIdx = toBeDeletedIdxs.get(j);
registeredApps.remove(deleteIdx);
}
registeredApps.add(app);
}
String result = "NA";
// 注册成功的应用时间段互不冲突,因此查询时间只会对应一个应用
for (Application registeredApp : registeredApps) {
if (queryTime >= registeredApp.startMinute && queryTime < registeredApp.endMinute) {
result = registeredApp.appName;
break;
}
}
return result;
}
public static int convert(String time) {
// 时间格式 HH:MM,小时和分钟都是两位,不足两位前面补0
String[] timeParts = time.split(":");
String hours = timeParts[0];
String minutes = timeParts[1];
return Integer.parseInt(hours) * 60 + Integer.parseInt(minutes);
}
}
题目内容
智能手机方便了我们生活的同时,也侵占了我们不少的时间。
“手机App防沉迷系统”能够让我们每天合理地规划手机App使用时间,在正确的时间做正确的事。
它的大概原理是这样的:
1.在一天24小时内,可以注册每个App的允许使用时段

2.一个时间段只能使用一个App,举例说明:不能同时在9:00−10:00注册App2和App3

3.App有优先级,数值越高,优先级越高。注册使用时段时,如果高优先级的App时间和低优先级的时段有冲突,则系统会自动注销低优先级的时段,如果App的优先级相同,则后添加的App不能注册。
举例1:
(1) 注册App3前

(2)App3注册时段和App2有冲突 
(3) App3优先级高,系统接受App3的注册,自动注销App2的注册 
举例2:
(1) 注册App4
(2) App4和App2及App3都有冲突,优先级比App2高,但比App3低,这种场景下App4注册不上,最终的注册效果如下 
4.一个App可以在一天内注册多个时段 
请编程实现,根据输入数据注册App,并根据输入的时间点,返回时间点使用的App名称,如果该时间点没有注册任何App,请返回字符串“NA”。
输入描述
第一行表示注册的App数量 N(N≤100)
第二部分包括 N 行,每行表示一条App注册数据
最后一行输入一个时间点,程序即返回该时间点使用的App
2
App1 1 09:00 10:00
App2 2 11:00 11:30
09:30
数据说明如下:
- N行注册数据以空格分隔,四项数依次表示:App名称、优先级、起始时间、结束时间
- 优先级1~5,数字越大,优先级越高
- 时间格式 HH:MM,小时和分钟都是两位,不足两位前面补0
- 起始时间需小于结束时间,否则注册不上
- 注册信息中的时间段包含起始时间点,不包含结束时间点
输出描述
输出一个字符串,表示App名称,或NA表示空闲时间
备注
- 用例保证时间都介于 00:00−24:00 之间;
- 用例保证数据格式都是正确的,不用考虑数据输入行数不够、注册信息不完整、字符串非法、优先级超限、时间格式不正确的问题;
样例1
输入
1
App1 1 09:00 10:00
09:30
输出
App1
说明
App1注册在9点到10点间,9点半可用的应用名是App1
样例2
输入
2
App1 1 09:00 10:00
App2 2 09:10 09:30
09:20
输出
App2
说明
App1和App2的时段有冲突,App2优先级高,注册App2之后,App1自动注销,因此输出App2。
样例3
输入
2
App1 1 09:00 10:00
App2 2 09:10 09:30
09:50
输出
NA
说明
App1被注销后,09:50时刻没有应用注册,因此输出NA