zoukankan      html  css  js  c++  java
  • hihoCoder 1401 Registration

    多队列模拟. 与POJ #1025 Department类似, 不过简化很多. 貌似这类模拟题经常出现. 用STL中的优先队列 (priority_queue<>) 很好写.


    这题我写得很不顺, 老年选手退步太快, 记录一下我犯的一个很隐蔽的错误, 从前对此毫无认识, 想想都可怕, 太菜了.

    这道题优先队列里维护的事件 (event) 是等待.
    释放这些等待的先后顺序如下:

    在同一队列 (此"队列"指某个office门前的队列, 与"优先队列"中的"队列"含义不同;下同) 中的两个事件, 按(开始等待时刻, 学号)这两个关键字排序. 在不同队列中的两事件按开始等待的时刻排序.

    思路是比较容易想到的. 但我的实现里有个很subtle的错误.

    Wrong implementation

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N{1<<14}, M{1<<7};
    int s[N], res[N];
    vector<pair<int,int>> r[N];   // registration
    int avail[M];
    int n, m, k;
    
    struct W{
        int id, beg, idx;
        int des()const{
            return r[id][idx].first;
        }
        int dur()const{
            return r[id][idx].second;
        }
        int num()const{
            return s[id];
        }
        int end()const{
            return max(beg, avail[des()])+dur();    // error-prone
        }
        W next(){
            return {id, end()+k, idx+1};
        }
        void out(){
            cout<<id<<' '<<beg<<' '<<idx<<' '<<avail[des()]<<endl;
        }
    };
    
    // greater<_Tp> is a function object
    // constexpr std::greater<_Tp>::operator()(const _Tp &, const_Tp &)const
    
    bool cmp(const W &a, const W &b){  //! > must be a const
        if(a.des()!=b.des()){
            return a.beg>b.beg;
        }
        else{
            return a.beg!=b.beg?a.beg>b.beg:a.num()>b.num();
        }
    }
    
    
    priority_queue<W, vector<W>, decltype(cmp)*> que(cmp);
    
    int main(){
        cin>>n>>m>>k;
        for(int i=0; i<n; i++){
            int q, t;
            cin>>s[i]>>t>>q;
            for(; q--; ){
                int o, t;
                cin>>o>>t;
                r[i].push_back({o, t});
            }
            que.push({i, t+k, 0});
        }
    
        for(; !que.empty(); ){
            W top=que.top();
            que.pop();
            if(top.idx<r[top.id].size()-1){
                que.push(top.next());
            }
            else{
                res[top.id]=top.end();
            }
            avail[top.des()]=top.end();
        }
        for(int i=0; i<n; i++)
            cout<<res[i]<<endl;
        return 0;
    }
    

    注意其中的比较函数cmp:

    bool cmp(const W &a, const W &b){  //! > must be a const
        if(a.des()!=b.des()){
            return a.beg>b.beg;
        }
        else{
            return a.beg!=b.beg?a.beg>b.beg:a.num()>b.num();
        }
    }
    

    首先必须认识到: 优先队列要求元素的键值 (key) 在所定义的比较函数下是全序的 (totally ordered).

    If $X$ is totally ordered under $le$, then the following statements hold for all $a, b$ and $c$ in $X$:
    if $a le b$ and $b le a$ then $ a=b$ (antisymmetry);
    if $a le b$ and $ble c$ then $a le c$ (transitivity);
    $a le b$ or $b le a$ (totality).

    我所定义的比较函数并不是全序的. 问题中的集合$X$内的元素是一个三元组$(id, des, time)$. 我们定义的比较函数cmp是一个strict weak ordering (<). 这个binary relation应当满足

    if $a < b$ and $b<c$, then $a<c$
    $a< b$ or $ b<a$ or $a=b$.

    但是据此会导出矛盾, 考虑

    $a =(id_1, des_1, t), b=(id_2, des_1, t), c=(id_3, des_2, t), id_1 < id_2 Longrightarrow a > b, a=c, b=c$.
    矛盾!

    因而这个比较函数不是全序的.
    但是可以略微改一下:

    以$time$为第一关键字, $des$为第二关键字, $id$为第三关键字.

    这样不但思路更清楚, 代码也可以简化

    Implementation

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N{1<<14}, M{1<<7};
    int s[N], res[N];
    vector<pair<int,int>> r[N];   // registration
    int avail[M];
    int n, m, k;
    
    struct W{
        int id, beg, idx;
        int des()const{
            return r[id][idx].first;
        }
        int dur()const{
            return r[id][idx].second;
        }
        auto make_tuple()const{
            return std::make_tuple(beg, des(), num());
        }
        int num()const{
            return s[id];
        }
        bool operator<(const W &rhs)const{
            return make_tuple() > rhs.make_tuple();
        }
        int end()const{
            return max(beg, avail[des()])+dur();    // error-prone
        }
        W next(){
            return {id, end()+k, idx+1};
        }
        void out(){
            cout<<id<<' '<<beg<<' '<<idx<<' '<<avail[des()]<<endl;
        }
    };
    
    priority_queue<W> que;
    
    int main(){
        cin>>n>>m>>k;
        for(int i=0; i<n; i++){
            int q, t;
            cin>>s[i]>>t>>q;
            for(; q--; ){
                int o, t;
                cin>>o>>t;
                r[i].push_back({o, t});
            }
            que.push({i, t+k, 0});
        }
    
        for(; !que.empty(); ){
            W top=que.top();
            que.pop();
            if(top.idx<r[top.id].size()-1){
                que.push(top.next());
            }
            else{
                res[top.id]=top.end();
            }
            avail[top.des()]=top.end();
        }
        for(int i=0; i<n; i++)
            cout<<res[i]<<endl;
        return 0;
    }
    
  • 相关阅读:
    如何避免重复的开发
    用BPM解决企业信息化的数据孤岛
    撸代码之前我们应该想些什么
    从开发的角度去分解项目需求
    MQTT 无法连接问题排查
    Linux下的OpenSSH,你知道多少?
    Linux下Rsyslog日志远程集中式管理
    如何在Linux下部署Samba服务?
    Linux环境下安装配置vsftpd服务(三种认证模式)
    Linux集群环境下NTP服务器时间同步
  • 原文地址:https://www.cnblogs.com/Patt/p/6028421.html
Copyright © 2011-2022 走看看