信息学奥赛一本通 1371:看病

【题目链接】

ybt 1371:看病

【题目考点】

1. 堆
2. 大量数据输入输出

当输入数据量达到 1 0 6 10^6 106规模,或输出数据量达到 1 0 5 10^5 105规模时,有以下两种输入输出方法:

  1. 用scanf/printf
  2. 解除IO同步,IO解绑
ios::sync_with_stdio(false);
cin.tie(0);

并使用cout << '\n'代替cout << endl;

【解题思路】

设结构体类型Person表示一个患者,包含属性:名字,病情优先级。
设优先队列(堆),里面保存Person类型的对象,优先级定义为:病情优先级高的人更优先。
输入数据,遇到push时,生成一个患者,加入优先队列。遇到pop时,取优先队列的队头(堆顶),而后出队(删除堆顶)。如果优先队列为空,输出none。
添加和删除的患者数量达到 1 0 5 10^5 105,如果使用优先队列(堆),那么添加、删除的复杂度都是 O ( l o g n ) O(logn) O(logn),整体复杂度为 O ( n l o g n ) O(nlogn) O(nlogn),是可行的。

【注意】该题输出数据量达到 1 0 5 10^5 105,因此要用scanf/printf来做输入输出,或解除IO同步,IO解绑。

【题解代码】

解法1:使用scanf/printf,使用优先队列
#include<bits/stdc++.h>
using namespace std;
struct Person
{
    char name[25];
    int level;
    bool operator < (const Person &b) const
    {
    	return b.level > level;//病情等级更高的更优先 
	}
};
int main()
{
    Person per;
    int n;
    char s[25];
    scanf("%d", &n);
    priority_queue<Person> pq;//大顶堆 
    for(int i = 1; i <= n; ++i)
    {
        scanf("%s", s);
        if(strcmp(s, "push") == 0)
        {
        	scanf("%s%d", per.name, &per.level);
            pq.push(per);
        }
        else//pop
        {
            if(pq.empty())
            	printf("none\n");
            else
            {
                per = pq.top();
                printf("%s %d\n", per.name, per.level);
                pq.pop();
            }
        }
    }
    return 0;
}
解法2:解除IO同步,IO解绑,手写堆
#include<bits/stdc++.h>
using namespace std;
#define N 100005
template<class T, class IsPriorClass>
class PriorityQueue//优先队列类 
{
private:
    T heap[N];
	int n;
	IsPriorClass isPrior;//仿函数对象:用于比较两元素的优先级 
    void shiftUp(int i)//第i结点上移 
    {
        if(i == 1)//p是根结点 
            return;
        if(isPrior(heap[i/2], heap[i]))
        {
            swap(heap[i], heap[i/2]);
            shiftUp(i/2);
        }
    }
    void shiftDown(int i)//第i结点下沉 
    {
        if(i > n/2)//如果i是叶子结点
            return; 
        int sel;//选择交换的结点位置 
        if(2*i+1 <= n && isPrior(heap[2*i],heap[2*i+1]))//有右孩子且右孩子值更大 
            sel = 2*i + 1;
        else//没有右孩子或左孩子值更大 
            sel = 2*i; 
        if(isPrior(heap[i],heap[sel]))
        {
            swap(heap[sel], heap[i]);
            shiftDown(sel); 
        }
    }
public:
    PriorityQueue()
    {
        n = 0;
    }
    void push(T val)//堆中插入元素 
    {
        heap[++n] = val;
        shiftUp(n); 
    } 
    void pop()//删除堆顶 
    {
        swap(heap[1], heap[n]);
        n--;
        shiftDown(1); 
    } 
    T top()//获取堆顶 
    {
        return heap[1];
    }
    bool empty()//判断堆为空 
    {
        return n == 0;
    }
    int size()//获取堆中元素个数 
    {
    	return n;
	}
};
struct Person
{
    string name;
    int level;
};
struct Cmp
{
    bool operator () (Person &a, Person &b)
    {
        return b.level > a.level;
    }
};
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
    Person per;
    int a, n;
    string s;
    cin >> n;
    PriorityQueue<Person, Cmp> pq;//病情等级更高的更优先 
    for(int i = 1; i <= n; ++i)
    {
        cin >> s;
        if(s == "push")
        {
            cin >> per.name >> per.level;
            pq.push(per);
        }
        else//pop
        {
            if(pq.empty())
                cout << "none\n";
            else
            {
                per = pq.top();
                cout << per.name << ' ' << per.level << '\n';
                pq.pop();
            }
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值