Python-算法编程100例-系统设计题(入门级)-疫情人员管理

题目描述:

现有一套用于管理疫情下人员流动风险的软件系统,请实现以下接口:

RiskMonitor(int[] people):系统初始化,people[i]的下标表示人员编号,值表示所在地区的编号。初始时所有地区(包括没人的地区)都为低风险,系统初始为第0天。

travel(int date, int peopleid, int regionid): 在第date天时,人员peopleid前往目的地regionid旅行。

a. 如果该人员已经在该地区regionid,则停留在原地,并返回1;

b. 如果该人员已经被隔离,或者目的地此时为高风险,则停留在原地,返回-1;

c. 否则旅行成功,该人员从date天(含)开始位于新地区,返回0。

increaseRisk(int date, int regionid): 第date天(含)时,地区regionid变成高风险。当前该地区人员立即被隔离。

decreaseRisk(int date, int regionid):在第date天(含)时,地区regionid变成低风险。

a. 如果该地区从date开始连续14天处于低风险,则第date+14天(含),所有该地区的被隔离人员立即解除隔离。

query(int date): 在第date天(含)时,按人员编号升序,依次返回每个人累计被隔离的天数。

输出保证:

a. 所有接口调用按照date非严格递增顺序

b. 同一天中,increaseRisk或者decreaseRisk调用排在所有travel调用之前,query调用排在所有其他调用之后

c. 同一天同一地区调用increaseRisk和decreaseRisk的次数之和不会超过一次(即风险不会来回切换)

d. 调用increaseRisk或decreaseRisk一定会产生风险切换(比如不会出现已经高风险地区再调用increaseRisk的情况)

样例:

输入

RiskMonitor([1,1])

travel([2, 1, 0])

increaseRisk(5, 1)

query(5)

travel(19,1,1)

decreaseRisk(21, 1)

query(22)

travel(25, 1, 1)

travel(35, 0, 0)

query(37)

输出:

null

0

null

[1, 0]

-1

null

[18, 0]

0

0

[30, 0]

题目解答:

# 现有一套用于管理疫情下人员流动风险的软件系统,请实现以下接口:
# RiskMonitor(int[] people):系统初始化,people[i]的下标表示人员编号,值表示所在地区的编号。初始时所有地区(包括没人的地区)都为低风险,系统初始为第0天。
# travel(int date, int peopleid, int regionid): 在第date天时,人员peopleid前往目的地regionid旅行。
# a. 如果该人员已经在该地区regionid,则停留在原地,并返回1;
# b. 如果该人员已经被隔离,或者目的地此时为高风险,则停留在原地,返回-1;
# c. 否则旅行成功,该人员从date天(含)开始位于新地区,返回0。
# increaseRisk(int date, int regionid): 第date天(含)时,地区regionid变成高风险。当前该地区人员立即被隔离。
# decreaseRisk(int date, int regionid):在第date天(含)时,地区regionid变成低风险。
# a. 如果该地区从date开始连续14天处于低风险,则第date+14天(含),所有该地区的被隔离人员立即解除隔离。
# query(int date): 在第date天(含)时,按人员编号升序,依次返回每个人累计被隔离的天数。

# 分析题意
# 对象(属性)
# # a. 如果该人员已经在该地区regionid,则停留在原地,并返回1;
# # b. 如果该人员已经被隔离,或者目的地此时为高风险,则停留在原地,返回-1;
# -->因此人员需要所在地区属性, 是否被隔离属性; 地区需要风险等级属性;
# people(编号, 所在区域, 是否被隔离)
# region(编号, 风险等级)

# 地区变成高风险,该地区所有人员立即被隔离
# 地区变成低风险,从date开始连续14天处于低风险,该地区所有隔离人员解除隔离
# -->因此地区需要有人员属性
# region(编号, 风险等级, 地区所有人员)  -->数据结构 regin_dict = {region_id: {"level": level, "peoples": [peoples]}}

# query(int date): 在第date天(含)时,按人员编号升序,依次返回每个人累计被隔离的天数。
# -->因此人员需要被隔离天数属性
# people(编号, 所在区域, 是否被隔离, 上次隔离天数, 隔离开始时间, 隔离结束时间)  --->数据结构 people_dict = {people_id: {
# "region_id": region, "status": status, "total_days": total_days, "start_day": start_day, "end_day": end_day}}

from typing import List
from collections import defaultdict

class RiskMonitor:
    def __init__(self, people: List[int]):
        # 保存每个区域的人员
        self.region_dict = defaultdict(list)
        # 保存每个区域的风险等级
        self.region_staus = defaultdict(int)
        # 保存每个人的状态
        self.people_dict = defaultdict(dict)
        # 初始化
        for people_id, region_id in enumerate(people):
            self.region_dict[region_id].append(people_id)
            self.region_staus[region_id] = 0
            self.people_dict[people_id] = {"region_id": region_id, "status": 0, "total_days": 0, "start_day": 0, "end_day": 0}
        print("null")

    def update_people(self, date):
        for people_status in self.people_dict.values():
            # 隔离的人状态需要更新
            if people_status["status"] == 1:
                if people_status["end_day"] > 0 and date > people_status["end_day"]:
                    total_days = people_status["total_days"] + people_status["end_day"] - people_status["start_day"] + 1
                    people_status["total_days"] = total_days
                    people_status["status"] = 0
                    people_status["start_day"] = 0
                    people_status["end_day"] = 0
                else:
                    total_days = people_status["total_days"] + date - people_status["start_day"] + 1
                    people_status["total_days"] = total_days
                    people_status["start_day"] = date + 1

    def travel(self, date: int, people_id: int, region_id: int) -> int:
        # 更新一下状态
        self.update_people(date)

        # 如果该人员已经在该地区regionid,则停留在原地,并返回1
        if self.people_dict[people_id]["region_id"] == region_id:
            print(1)
            return 1
        # 如果该人员已经被隔离,或者目的地此时为高风险,则停留在原地,返回 - 1
        if self.people_dict[people_id]["status"] == 1 or self.region_staus[region_id] == 1:
            print(-1)
            return -1
        # 否则旅行成功,该人员从date天(含)开始位于新地区,返回0
        # 从旧区域中移除该人员
        self.region_dict[self.people_dict[people_id]["region_id"]].remove(people_id)
        # 更新该人员所在区域为新区域
        self.people_dict[people_id]["region_id"] = region_id
        # 在新区域中人员列表中增加该人员
        self.region_dict[region_id].append(people_id)
        print(0)
        return 0


    def increase_risk(self, date: int, region_id: int) -> int:
        # 第date天(含)时,地区regionid变成高风险。当前该地区人员立即被隔离
        self.update_people(date-1)

        self.region_staus[region_id] = 1
        for people_id in self.region_dict[region_id]:
            self.people_dict[people_id]["status"] = 1
            self.people_dict[people_id]["start_day"] = date
            self.people_dict[people_id]["end_day"] = 0
        print("null")

    def decrease_risk(self, date: int, region_id: int) -> int:
        # 在第date天(含)时,地区regionid变成低风险
        # a. 如果该地区从date开始连续14天处于低风险,则第date+14天(含),所有该地区的被隔离人员立即解除隔离。
        self.region_staus[region_id] = 0

        for people_id in self.region_dict[region_id]:
            self.people_dict[people_id]["end_day"] = date + 13

        # 更新当天的状态
        self.update_people(date)
        print("null")

    def query(self, date: int) -> List[int]:
        # 更新一下当天状态
        self.update_people(date)
        query_list = []
        for value in self.people_dict.values():
            query_list.append(value["total_days"])
        print(query_list)
        return query_list

总结:

1、根据题目描述列出对象及其属性,有些属性根据题目描述就可以得到, 有些属性需要根据题目内容和实际要求解的结果自定义。

2、根据对象及其属性选择合适的数据结构,例如字典套字典,字典套列表等。

3、各个对象之前存在某种关联关系。

对象1(属性1,属性2...)

对象2(属性2, 属性2, 属性3...)

对象3(属性1...)

  • 7
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值