HDU 1873 看病要排队( 优先队列模拟)

本文介绍了一个基于优先级的医院就诊队列模拟程序,通过三种不同优先级队列实现病人的入队和出队操作,确保紧急病人能够优先得到治疗。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Problem Description

看病要排队这个是地球人都知道的常识。
不过经过细心的0068的观察,他发现了医院里排队还是有讲究的。0068所去的医院有三个医生(汗,这么少)同时看病。而看病的人病情有轻重,所以不能根据简单的先来先服务的原则。所以医院对每种病情规定了10种不同的优先级。级别为10的优先权最高,级别为1的优先权最低。医生在看病时,则会在他的队伍里面选择一个优先权最高的人进行诊治。如果遇到两个优先权一样的病人的话,则选择最早来排队的病人。

现在就请你帮助医院模拟这个看病过程。

 

 

Input

输入数据包含多组测试,请处理到文件结束。
每组数据第一行有一个正整数N(0<N<2000)表示发生事件的数目。
接下来有N行分别表示发生的事件。
一共有两种事件:
1:"IN A B",表示有一个拥有优先级B的病人要求医生A诊治。(0<A<=3,0<B<=10)
2:"OUT A",表示医生A进行了一次诊治,诊治完毕后,病人出院。(0<A<=3)

 

 

Output

对于每个"OUT A"事件,请在一行里面输出被诊治人的编号ID。如果该事件时无病人需要诊治,则输出"EMPTY"。
诊治人的编号ID的定义为:在一组测试中,"IN A B"事件发生第K次时,进来的病人ID即为K。从1开始编号。

 

 

Sample Input

 

7 IN 1 1 IN 1 2 OUT 1 OUT 2 IN 2 1 OUT 2 OUT 1 2 IN 1 1 OUT 1

 

 

Sample Output

 

2 EMPTY 3 1 1

 

 

Author

linle

 

 

Source

2008浙大研究生复试热身赛(2)——全真模拟

 

 

Recommend

lcy   |   We have carefully selected several similar problems for you:  1871 1509 1872 1876 1875 


 

复习优先队列...(忘了开队列数组了)


#include<bits/stdc++.h>
//#pragma GCC optimize(2)
using namespace std;
#define maxn 105
#define inf 1e18
//#define mod 1e9+7
typedef long long ll;
const ll mod = 1e9+7;
ll n;
struct Why
{
    ll n,vi;
    Why(ll x,ll y)
    {
        n = x;
        vi = y;
    }
    bool operator < (const Why a) const
    {
        if(vi != a.vi)
            return vi < a.vi;
        else
            return n > a.n;
    }
};
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);

    while(cin >> n)
    {
        priority_queue<Why>A,B,C;
        string str;
        ll a,b,num = 1;
        while(n--)
        {
            cin >> str;
            if(str == "IN")
            {
                cin >> a >> b;
                if(a == 1)
                {
                    A.push( Why(num,b));
                    num++;
                }
                else if(a == 2)
                {
                    B.push( Why(num,b));
                    num++;
                }
                else if(a == 3)
                {
                    C.push( Why(num,b));
                    num++;
                }
            }
            else if(str == "OUT")
            {
                ll a;
                cin >> a;
                if( a == 1 )
                {
                    if(A.size()!=0)
                    {
                        Why t = A.top();
                        A.pop();
                        cout << t.n << endl;
                    }
                    else
                        cout << "EMPTY" << endl;
                }
                else if(a == 2)
                {
                    if(B.size()!=0)
                    {
                        Why t = B.top();
                        B.pop();
                        cout << t.n << endl;
                    }
                    else
                        cout << "EMPTY" << endl;
                }
                else if(a == 3)
                {
                    if(C.size()!=0)
                    {
                        Why t = C.top();
                        C.pop();
                        cout << t.n << endl;
                    }
                    else
                        cout << "EMPTY" << endl;
                }
            }

        }
    }



    return 0;
}

 

<think>好的,我现在需要分析HDU1873题目中看病排队算法的时间复杂度。首先,我得先理解题目要求和具体的算法实现。题目描述有三个医生,每个医生有一个排队队列,病人根据优先级(1-10,10最高)排队,同优先级则按到达顺序处理。每次处理时,医生会选择自己队列中优先级最高的病人,同优先级的选最早来的。 接下来,我得想这个问题的典型解法是怎样的。根据ACM题目的常见做法,通常会使用优先队列(堆)来处理这种动态选择最高优先级的场景。每个医生对应一个优先队列,队列中的元素需要比较优先级和到达时间。不过,因为优先队列通常只能根据一个键排序,所以可能需要将优先级和到达时间结合起来,比如存储为元组,并自定义比较函数,使得首先按优先级降序排列,同优先级时按到达时间升序排列。 现在考虑时间复杂度。每个操作包括病人的入队和医生的处理(出队)。假设总共有n次操作,每次操作要么是病人排队(入队),要么是医生看诊(出队)。需要分析这两种操作的时间复杂度。 对于优先队列(通常用堆实现),入队操作的时间复杂度是O(log k),其中k是该医生队列当前的长度。出队操作同样也是O(log k),因为取出堆顶后需要调整堆结构。那么,如果有n次操作,最坏情况下,每次都是入队或出队,假设平均每个医生的队列处理大约n/3次操作(三个医生均分),那总的时间复杂度应该是O(n log m),其中m是队列的最大长度。但更准确地说,每个入队和出队都是O(log k),k随着操作而变化。但总体来看,所有操作的总时间复杂度是O(n log n),因为每个元素最多被入队和出队各一次,每次操作的堆调整时间是O(log n),所以总时间是O(n log n)。 但是,这里需要注意,当医生处理病人时,可能需要从三个医生中选择哪个来处理输出?题目中的输入指令是当有“OUT”事件时,指定医生编号,所以处理出队时只需要对该医生的队列进行操作,不需要遍历三个医生。因此,每次OUT操作对应的是特定医生的队列出队,时间复杂度是该队列的堆调整时间。 因此,整个算法的时间复杂度主要取决于所有入队和出队操作的总和。每个入队和出队都是O(log k),而k最大可能达到n(如果所有病人都排到一个医生的队列里)。所以,最坏情况下时间复杂度是O(n log n)。 有没有可能的优化?比如,当优先队列的实现方式不同,或者是否有可能某些情况下时间复杂度更低?例如,如果使用不同的数据结构,比如有序链表,那插入操作的时间复杂度会更高。而使用堆是最优的选择,因为插入和删除都是对数时间。 此外,题目中的比较条件需要考虑优先级和到达时间的组合。对于优先队列的实现,可能需要将这两个因素结合起来作为排序的关键字。例如,将优先级取负数,这样堆默认是最小堆,而实际是按优先级降序排列;同时,到达时间作为第二关键字,升序排列。这样每次插入和取出都能保证正确顺序。 总结,该算法的时间复杂度为O(n log n),其中n是操作的总次数。这是因为每个病人的入队和出队操作的时间复杂度都是对数级别的,而总共有n次这样的操作。</think>### HDU1873 看病排队算法时间复杂度分析 对于HDU1873题目中的看病排队算法,其时间复杂度主要取决于数据结构和操作逻辑的设计。以下是具体分析: --- #### **1. 核心数据结构** 通常采用**优先队列(堆)**实现医生队列管理,每个医生的队列独立存储病人信息。病人属性包括: - **优先级**(数值越大优先级越高) - **到达时间**(用于处理同优先级时的顺序) **数据结构定义示例**: ```python import heapq class Patient: def __init__(self, priority, time): self.priority = -priority # 取负数实现最大堆 self.time = time def __lt__(self, other): if self.priority == other.priority: return self.time < other.time return self.priority < other.priority ``` --- #### **2. 时间复杂度分析** 假设总操作次数为$n$,包含入队(`IN`)和出队(`OUT`)两类操作: 1. **入队操作(`IN`)** - 将病人插入对应医生的优先队列,时间复杂度为$O(\log k)$,其中$k$为当前队列长度。 - 最坏情况下,所有病人集中在同一医生队列,次操作复杂度为$O(\log n)$。 2. **出队操作(`OUT`)** - 从医生的优先队列中弹出堆顶元素,时间复杂度为$O(\log k)$。 - 若队列为空,直接返回无病人信息,时间复杂度$O(1)$。 **总时间复杂度**: 所有操作的总时间复杂度为$O(n \log n)$,因为每个病人最多经历一次入队和一次出队,每次操作平均复杂度为$O(\log n)$[^1]。 --- #### **3. 优化对比** - **堆 vs 有序链表** 堆的插入/删除效率为$O(\log n)$,优于有序链表的$O(n)$。 - **多关键字排序** 通过自定义比较函数(优先级+到达时间),可避免遍历队列查找最高优先级病人,直接通过堆结构维护顺序。 --- #### **4. 性能边界** - **最好情况**:所有操作均为出队且队列为空,时间复杂度$O(n)$。 - **最坏情况**:所有病人集中在同一队列,时间复杂度严格为$O(n \log n)$。 --- #### **5. 实际应用验证** 在HDU1873的AC代码中,使用优先队列的实现方式可通过所有测试用例[^1],验证了$O(n \log n)$时间复杂度的有效性。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值