STL容器

第四节、 STL容器的使用

一、STL的概念

  1. STL: 标准模板库
  2. STL的六大组件:
    1. 容器
    2. 算法
    3. 迭代器
    4. 适配器
    5. 仿函数
    6. 分配器

二、string的简单用法(cppreference.com)

  1. 头文件
  2. 字符串的连接 直接 str += “123”;
  3. 按照字典序直接<=>比较
  4. string.size() 长度—》 length()
  5. 字符串的查找 string.find(“内容”, 位置), 找不到 string::npos
  6. 字符串的插入: string.insert(位置, ”内容“);
  7. 字符串的截取 string.substr(位置, 长度), 长度不写默认截取到最后
  8. 字符串的替换: str.replace(位置, 长度, ”内容")
  9. 字符串的反转: reverse(str.begin(), str.end());—>头文件 algorithm
#include<iostream>
#include <string>
#include <algorithm>

using namespace std;



int main() {
    string str = "abc";
    str += "12345";
    cout << str << endl;  //str = "abc12345"
    for (int i = 0; i < str.size(); i++) {
        cout << str[i] ;//abc12345
    }
    cout << " " << str.length() << endl;
    if (str.find("c12") != string::npos) { //不等于找不到,就是找到了
        cout << "yes  " << str.find("c12" ) << endl;//输出位置 2
    }
    if (str.find("c12", 4) == string::npos) {//4的位置是否是c12
        cout << "no" << endl;
    }
    str.insert(5, "xyz");//在5的位置插入xyz 
    cout << str << endl;
    string temp = str.substr(3, 2); //从位置3开始,截取长度为2的字符串
    cout << temp << endl;
    str.replace(2, 2, "999"); 
    cout << str << endl;
    reverse(str.begin(), str.end());//反转str
    cout << str << endl;

    return 0;
}

结果:

abc12345
abc12345  8
yes 2
no
abc12xyz345
12
ab9992xyz345
543zyx2999ba

三、vector

  1. 可以理解为动态数组,由片连续的内存组成

  2. vector v( num, cnt)

    vector<int> v(5, 1);
    定义一个vector类型的int型容器,初始化5个内存大小,并将这些内存空间的值初始化为1 ,v[0] ~ v[4]
    
  3. vector.size() 返回元素数量

  4. vector.push_back(x) —>尾部插入x

  5. vector的扩容操作:

#include<iostream>
#include<vector>
using namespace std;


int main() {
   
    //扩容
    /*
    不同编译器,扩容不同,有可能是2倍扩容,有可能是1.5之类的
    */
  
    vector<int> v;
    int temp = -1;
    for (int i = 0; i < 10000; i++) {
        if (temp != v.capacity()) {
            temp = v.capacity();//容器上限
            cout << temp << endl;
        }
        v.push_back(i);
    }

    //二维
    //
    
    vector<vector<int> > m(5, vector<int>(6, 9));//初始化为5行6列的元素为9的矩阵
    for(int i = 0; i < m.size(); i++) {
        for (int j = 0; j < m[i].size(); j++) {
            cout << m[i][j] << " ";
        }
        cout << endl;
    }


    return 0;
}

四、stack(栈容器–》先进后出)

  1. 本质是一个适配器—双端队列

  2. 头文件—

  3. sta.push(x) -->插入栈顶元素

    sta.pop() —> 弹出栈顶元素

    sta.top() —>访问栈顶元素

    sta.empty() -->是否为空

#include<iostream>
#include<stack>
using namespace std;

int main() {
    stack<int> sta;
    sta.push(7);
    sta.push(10);
    sta.push(2);
    sta.push(6);
    cout << sta.size() << endl;
    cout << sta.top() << endl;
    while(!sta.empty()) {
        cout << sta.top() << endl;
        sta.pop();
    }
    cout << sta.size() << endl;
    return 0;
}
//注意:如果栈为空时,还去访问栈顶元素,会报错

五、queue容器(队列–》先进先出》

  1. 本质时队列的适配器:

  2. 头文件—》

  3. queue que

  4. que.push(x)

    que.pop();

    que.emtpy();

    que.front();//队首

    que.back(); // 队尾元素

//自定义结构的使用

#include <iostream>
#include<queue>
using namespace std;

struct node {
    int x, y;
};

int main() {
    queue<node> que;
    que.push((node){5, 6});
    que.push((node){1, 8});
    que.push((node){2, 9});
    while (que.empty()) {
        node temp = que.front();
        cout << temp.x << " " << temp.y << endl;
        que.pop();
    }

    return 0;
}

六、双端队列

  1. 本质是一个容器

    维护一块内存表,每个指针指向一个数据,内存不是连续的,但由于内存表的存在,可以直接访问

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lmxGgbuJ-1626452258069)(C:\Users\戴子儒\AppData\Roaming\Typora\typora-user-images\image-20210715232445863.png)]

  2. deque que;

  3. que.push_front(x) que.pop _front()

    que.push_back(x) que.pop_back()

    que.front() 访问队首 que.back() 访问队尾

七、优先队列priority_queue

  1. 优先级最高的队首元素先操作,

  2. 用堆来存储的(head)-- 》堆可以理解为用数组模拟的二叉树(树根的优先级最高)

  3. 访问 — O(1) 存储调整—O(logn)

  4. 头文件

    priority_queue<int> que; 默认时大顶堆
    que.size()元素个数   que.push(x)插入   que.pop()弹出   que.top()访问 que.empty()
    
    #include<iostream>
    #include <queue>
    using namespace std;
    int main() {
        prioroty_queue que;
        que.push(6);
        que.push(2);
        que.push(3);
        que.push(8);
        que.push(9);
        cout << que.size() << endl;
        while(!que.emoty()) {
              cout << que.top() << endl;//9 8  6  3 2
              que.pop();
        }
        return 0;
    }
    

    实现小根堆

    priority_queue<int , 容器, 比较方法> que

    #include <iosteam>
    #include <queue>
    #include <functional>//对应greater这个比较函数
    using namespace std;
    
    int main() {
        priority_queue<int, vector<int>, greater<int> > que;
        //如果不写后面两个参数,默认是vector<int>   less<int>,greater这里可以自定义的cmp
        que.push(6);
        que.push(2);
        que.push(3);
        que.push(8);
        que.push(9);
        cout << que.size() << endl;
        while(!que.emoty()) {
              cout << que.top() << endl;//2 3 6 8 9 
              que.pop();
        }
        return 0;
    }
    

    实现自定义使用

    #include <iosteam>
    #include <queue>
    #include <functional>//对应greater这个比较函数
    using namespace std;
    struct node {
        int x, y;
        bool operator< (const node &b) const {
            return this-> x < b.x;//重载小于号
        }
    };
    
    int main() {
        priority_queue<node> que;
        que.push((node){6, 8});
        que.push((node){2, 9});
        que.push((node){7, 5});
        while(!empty()) {
           cout << que.top().x << " " << que.top().y << endl;//x大的先输出
            que.pop();
        }
        
        
        return 0;
    }
    

八、set的简单用法

  1. 可以理解为集合,可以排序,可以去重

  2. 头文件 set s;

  3. 操作:O(logn)

    s.insert(5) 插入5

    s.erase(5)删除5

​ s.count(5)返回集合中元素为5的个数,但由于集合是没有重复的元素的,所以结果只能是0或者1,可以是用来看一个元素是否存在

  1. 默认排序时从小到大(红黑树,是有顺序的),自动从小到大排序
#include <iostream>
#inlcude <set>
using namespace std;
int main() {
    set<int> s;
    s.insert(2);
    s.inset(5);
    s.insert(3);
    s.insert(9);
    s.insert(6);
    cout << s.size() << endl;
    if(s.cout(1) == 1) {
        cout << "yes" << endl;
    }
    是。erase(2);
    for (auto it = s.begin(); it != s.end(); it++) {//定义一个迭代器,自动查找类型
        cout<< *it << " "; //小到大输出
    }
    cout << endl;
    return 0;
}

实现自定义结构使用set

#include <iostream>
#inlcude <set>
using namespace std;

struct node {
    int x, y;
    bool operator< (const node &b) const{
        return this->x < b.x;
    }
};

int main() {
    set<node> s;
    s.insert((node){4, 5});
    s.insert((node){3, 9});
    s.insert((node){2, 8});
    for (auto it = s.begin(); it != s.end(); it++) {//定义一个迭代器,自动查找类型
        cout<< it->x << " " << it->y << endl;; //按照x小到大输出
    }
    //反向迭代器
    for(auto it = s.rbegin(); it != s.rend(); it++) {
        cout << it->x << " " << it->y << endl;//由于时反向的迭代器,所以这个按照x从大到小输出
    }
    return 0;
}

九、map(键值对–>set的升级版)

  1. 键值对: pair<char, int> --> pair<‘A’, 5> —> p.first=‘A’, p.sceond= 5,map里面装的就是很多的pair键值对

  2. map<char, int> m; char是键的类型,排序按照这个来,int是值的类型

  3. 操作:

    插入:m.insert(mark_pair(‘B’, 12)); B对应12的键值对---->头文件****

    元素数量:m.size()

    查找:m.count(x) -->找到返回1,否则0, 元素不可能重复

    删除: m.erase(x)

    访问: m[‘B’] -->)(logn)

    #include<iostream>
    #include <map>
    #include <utility>//对应下面的mark_pair
    using namespace std;
    
    int main() {
        map<char, int> m;
        m.insert(mark_pair('B', 12));
        m['.'] = 15;
        m['z'] = 5;
        m['*'] = 7;
        m['>'] = 35;
        if(m.count('.') == 1) {
            cout << m['.'] << endl; 
        }
        m.erase('.');
        //自动按照字典序排序输出
        for(auto it = m.begin(); it != m.end(); it++) {
            cout << it->first << " " << it->second << endl;
        }
        return 0;
    }
    
    

​ multiset 、 multimap(不可以通过[]去访问了) 可以实现元素的重复

十、 unordered_set、unordered_map(哈希结构)

  1. 头文件<unordered_set> 和<unordered_map>
  2. 不再是有序的
  3. 复杂度由O(logn) —>O(平均常数)
#inlclude<iostream>
#include<unordered_map>
#include<string>
using namespace std;

int main() {
    unordered_map<string, int> m;
    m['123456'] = -999;
    m['123'] = 99;
    m['asaghds']= 438924;
    for (auto it = m.begin(); it != m.end(); it++) {
        cout << it->first << " " << it->second << endl;
    }
    return 0;
}

十一、例题

1. oj-379仓库日志

题目描述

某仓库购入新的货物(每次购入的货物均不同)并将一部分老货物发出,这个过程会有软件对数据以日志形式保存,规则如下:

该日志记录了两类操作:第一类操作为入库操作,以及该次入库的货物数量;第二类操作为出库操作。这些记录都严格按时间顺序排列。入库和出库的规则为先进后出,即每次出库操作货物为当前在仓库里所有货物中最晚入库的货物。

为了便于分析,现在加入了第三类查询操作,每次查询时,输出当前仓库数量最多的货物的数量。

输入

包含N+1 行:

第一行为 1个正整数 N,对应于日志内所含操作的总数。

接下来的 N 行,分别属于以下三种格式之一:

格式 1: 0 X//一次入库操作,正整数 XX 表示该次入库的货物的数量

格式 2: 1 //一次出库操作,(就当时而言)最后入库的货物出库

格式 3:2 //一次查询操作,要求分析程序输出当前仓库内数量最多的货物的数量

当仓库为空时你应该忽略出库操作,当仓库为空查询时你应该输出 0。

初始时仓库状态为空。

输出

输出行数等于日志中查询操作的次数。每行为一个正整数,表示查询结果。

样例输入

13
0 1
0 2
2
0 4
0 2
2
1
2
1
1
2
1
2

样例输出

2
4
4
1
0

数据规模与约定

时间限制:1 s

内存限制:256 M

100% 的数据保证 N≤200000,X≤108N≤200000,X≤108


分析:这题,仓库的货物去取出,很明显就是后进的先出,所以符合我们的stack栈结构,问题就在于我们需要输出栈中货物最多的值,所以我们需要新开一个栈,每次货物栈入栈时,我们把当前最多的货物放到极大值栈中就好了。

#include<stack>
#include<cstdio>
using namespace std;
int main() {
    stack<int> good, mmax;
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        int t;
        int num;
        scanf("%d", &t);
        if(t == 0) {
            scanf("%d", &num);
            good.push(num);
            if (mmax.empty() || mmax.top() < num) {
                mmax.push(num);
            } else {
                mmax.push(mmax.top());
            }
        } else if (t == 1) {
            if(!good.empty()) {
                good.pop();
                mmax.pop();
            }
        } else {
            if (!mmax.empty()) {
                printf("%d\n", mmax.top());
            } else {
                printf("0\n");
            }
        }
    }

    return 0;
}

2. oj-569溶液模拟器

题目描述

小 Y 虽然有很多溶液,但是还是没有办法配成想要的溶液,因为万一倒错了就没有办法挽回了。他从网上下载了一个溶液配制模拟器:模拟器在计算机中构造一种虚拟溶液,然后可以虚拟地向当前溶液中加入一定浓度、一定质量的这种溶液,模拟器会快速地算出倒入后虚拟溶液的浓度和质量。

模拟器的使用步骤如下:

(1) 为模拟器设置一个初始质量和浓度 V0、C0%(0≤C0≤1000≤C0≤100)。

(2)进行一系列的操作,模拟器支持的两种操作:一种是 P(v,c)) 操作,表示向当前的虚拟溶液中加入质量为 v 、浓度为 c 的溶液;另一种是 Z 操作,即撤销上一步P 操作。

输入

第 11 行两个整数 V0C0。

第 2 行 1 个整数 n ,n≤10000,表示操作数。

接下来的 n 行,每行一条操作,格式为:P v c 或 Z。当只剩下初始溶液的时候,再撤销就没有用了。

任意时刻质量都不会超过 231−1

输出

输出 n 行,每行两个数 ViCi,之间用一个空格隔开,其中 Vi 为整数,Ci 为实数(保留 5 位小数)。其中,第 ii 行表示第 ii 次操作后的溶液质量和浓度。

样例输入

100 100
2
P 100 0
Z

样例输出

200 50.00000
100 100.00000

数据规模与约定

时间限制:11 s

内存限制:6464 M

#include<iostream>
#include <stack>
#include <cstdio>
using namespace std;

struct node {
    double v, c, salt;
};


int main() {
    double v0, c0, salt0;
    int n;
    cin >> v0 >> c0 >> n;
    salt0 = v0 * c0 / 100;
    stack<node> sta;
    for (int i= 0; i < n; i++) {
        char t;
        cin >> t;
        if (t == 'P') {
            double vt , ct, saltt;
            cin >> vt >> ct;
            saltt = vt * ct / 100;
            sta.push((node){vt, ct, saltt});
            v0 += vt;
            salt0 += saltt;
        } else {
            if (!sta.empty()) {
                v0 -= sta.top().v;
                salt0 -= sta.top().salt;
                sta.pop();
            }
        }
         printf("%d %.5f\n", (int)v0, salt0 / v0 * 100);
    }
    return 0;
}

3. oj-385-海港

题目描述

小李是一个海港的海关工作人员,每天都有许多船只到达海港,船上通常有很多来自不同国家的乘客。

小李对这些到达海港的船只非常感兴趣,他按照时间记录下了到达海港的每一艘船只情况;对于第 i 艘到达的船,他记录了这艘船到达的时间 ti (单位:秒),船上的乘 客数 ki,以及每名乘客的国籍 xi,1,xi,2,…,xi,k。

小李统计了 n 艘船的信息,希望你帮忙计算出以每一艘船到达时间为止的 24 小时( 24 小时= 86400 秒)内所有乘船到达的乘客来自多少个不同的国家。

形式化地讲,你需要计算 nn 条信息。对于输出的第 ii 条信息,你需要统计满足 ti−86400<tp≤ti 的船只 p,在所有的 xp,j中,总共有多少个不同的数。

输入

第一行输入一个正整数 n,表示小李统计了 n 艘船的信息。

接下来 n 行,每行描述一艘船的信息:前两个整数 ti 和 ki 分别表示这艘船到达海港的时间和船上的乘客数量,接下来 ki 个整数 xi,j 表示船上乘客的国籍。

保证输入的 ti 是递增的,单位是秒;表示从小李第一次上班开始计时,这艘船在第 ti 秒到达海港。

输出

输出 n 行,第 i行输出一个整数表示第 i 艘船到达后的统计信息。

样例输入1

3
1 4 4 1 2 2
2 2 2 3
10 1 3

样例输出1

3
4
4

样例输入2

4
1 4 1 2 2 3
3 2 2 3
86401 2 3 4
86402 1 5

样例输出2

3
3
3
4

样例说明1

第一艘船在第 1 秒到达海港,最近 24 小时到达的船是第一艘船,共有 4 个乘客, 分别是来自国家 4,1,2,2,共来自 3 个不同的国家;

第二艘船在第 2 秒到达海港,最近 24 小时到达的船是第一艘船和第二艘船,共有 4+2=6个乘客,分别是来自国家 4,1,2,2,2,3,共来自 4 个不同的国家;

第三艘船在第 10 秒到达海港,最近 24 小时到达的船是第一艘船、第二艘船和第 三艘船,共有 4+2+1=7个乘客,分别是来自国家 4,1,2,2,2,3,3,共来自 4 个不同的国家。

样例说明2

第一艘船在第 1 秒到达海港,最近 24 小时到达的船是第一艘船,共有 4 个乘客,分别是来自国家 1,2,2,3,共来自 3 个不同的国家。

第二艘船在第 3 秒到达海港,最近 24 小时到达的船是第一艘船和第二艘船,共有 4+2=6个乘客,分别是来自国家 1,2,2,3,2,3共来自 3 个不同的国家。

第三艘船在第 86401秒到达海港,最近 24 小时到达的船是第二艘船和第三艘船,共有 2+2=4个乘客,分别是来自国家 2,3,3,4,共来自 3 个不同的国家。

第四艘船在第 86402秒到达海港,最近 24 小时到达的船是第二艘船、第三艘船和第四艘船,共有 2+2+1=5个乘客,分别是来自国家 2,3,3,4,5,共来自 4 个不同的国家。

数据规模与约定

时间限制:1 s

内存限制:256 M

100% 的数据保证 ti≤109,ki≤50其余所有输入数据均 ≤105

#include<queue>
#include <cstdio>
using namespace std;

struct node {//人到达的时间、国家
    int t, c;
};

int n, mark[100005], ans;

int main() {

    queue<node> que;
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        int t, cnt;
        scanf("%d%d", &t, &cnt);
        while(!que.empty() && t - que.front().t >= 86400) {
            mark[que.front().c]--;
            if(mark[que.front().c] == 0) ans--;
            que.pop();
        }
        for (int i = 0; i < cnt; i++) {
            int temp;
            scanf("%d", &temp);
            que.push((node){t, temp});
            mark[temp]++;
            if(mark[temp] == 1) ans++;
        }
        printf("%d\n", ans);
    }


    return 0;
}

4.oj -576最大收益

题目描述

商店里有 n 种商品和 k 个按顺序给出的订单。每种商品给定名称、收益和库存。每个订单给出需求商品和需求数量。编程判断是否能依序满足所有的订单,如果可以,输出收益;否则,输出“−X”,X 表示第一个无法满足的订单编号。

输入

第 1 行 2 个整数 n 和 k,k≤n≤105。

下面的 n行,每行表示一种商品的名称、收益和库存 3 种信息。

再下面的若干行,每行表示一个订单的需求商品和需求数量两种信息。

每种商品的个数保证在 int 范围内,保证每个订单中都不会出现没有的商品,商品名的长度≤20。

具体格式参见输入样例。

输出

一行一个整数,表示收益,或者“−X”“−X”,XX 表示第一个无法满足的订单编号。

样例输入

3 5
apple 1 100
pear 5 90
football 30 10
pear 24
apple 18
football 4
pear 1
football 6

样例输出

443

数据规模与约定

时间限制:11 s

内存限制:3232 M

#include<iostream>
#include<map>
#include<string>
using namespace std;


int main() {
    map<string, long long> m, cnt;
    int n, k;
    cin >> n >> k;
    for (int i = 0; i < n; i++) {
        string t;
        int t1, t2;
        cin >> t >> t1 >> t2;
        m[t] = t1;
        cnt[t] = t2;
    }
    long long ans = 0;
    for (int i = 1; i <= k; i++) {
        string t;
        int t3, temp;
        cin >> t >> t3;
        temp = cnt[t];
        if (temp >= t3) {
            temp -= t3;
            ans += t3 * m[t];
        } else {
            cout << -i << endl;
            return 0;
        }
    
    }
    cout << ans << endl;
    return 0;
}

5、oj-566上网统计

题目描述

在一个网络系统中有 N 个用户、 M 次上网记录。每个用户可以自己注册一个用户名,每个用户名只包含小写字母且长度小于 1000 的字符串,每次上网日志里都会有记录,现在请统计每个用户每次浏览了多少个网页。

输入

第 1行包含两个正整数 N (1≤N≤1000) 和 M (1≤M≤5000)。

第 2 ~ M+1 行,每行包含 2 个字符串,分别表示用户名和浏览的网页名。

输出

共 N 行,每行的第一个字符串时用户名,接下来的若干字符串是这个用户依次浏览的网页名(之间用一个空格隔开)。按照用户名出现的次序排序输出。

样例输入

5 7
goodstudyer bookshopa
likespacea spaceweb
goodstudyer bookshopb
likespaceb spaceweb
likespacec spaceweb
likespacea juiceshop
gameplayer gameweb

样例输出

goodstudyer bookshopa bookshopb
likespacea spaceweb juiceshop
likespaceb spaceweb
likespacec spaceweb
gameplayer gameweb

数据规模与约定

时间限制:11 s

内存限制:256256 M

#include<iostream>
#include<map>
#include <vector>
#include <string>
using namespace std;

int main() {
    int n, k, cnt = 0;
    cin >> n >> k;
    map<string, int> m;
    vector<vector<string> > ans(n, vector<string>());//初始化为n行的vector
    for (int i = 0; i < k; i++) {
        string user, web;
        cin >> user >> web;
        if (m.count(user) == 0) {
            m[user] = cnt;//对应的下标
            cnt++;
            ans[m[user]].push_back(user);
        }
        ans[m[user]].push_back(web);
    }
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < ans[i].size(); j++) {
            if(j != 0) {
                cout << " ";
            }
            cout << ans[i][j];
        }
        cout << endl;
    }


    return 0;
}

6、oj-287 合并果子(优先队列)

题目描述

在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。多多决定把所有的果子合成一堆。

每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。可以看出,所有的果子经过 n−1 次合并之后,就只剩下一堆了。多多在合并果子时总共消耗的体力等于每次合并所耗体力之和。

因为还要花大力气把这些果子搬回家,所以多多在合并果子时要尽可能地节省体力。假定每个果子重量都为 11,并且已知果子的种类数和每种果子的数目,你的任务是设计出合并的次序方案,使多多耗费的体力最少,并输出这个最小的体力耗费值。

例如有 33 种果子,数目依次为 1,2,9。可以先将 1、2 堆合并,新堆数目为 3,耗费体力为 3。接着,将新堆与原先的第三堆合并,又得到新的堆,数目为 12,耗费体力为 12。所以多多总共耗费体力为 3+12=15。可以证明 15 为最小的体力耗费值。

输入

输入包括两行,第一行是一个整数 n(1≤n≤10000),表示果子的种类数。

第二行包含 n 个整数,用空格分隔,第 i个整数 ai(1≤ai≤20000)是第 i种果子的数目。

输出

输出包括一行,这一行只包含一个整数,也就是最小的体力耗费值。输入数据保证这个值小于 231。

样例输入

3 
1 2 9 

样例输出

15

数据规模与约定

时间限制:1 s

内存限制:256 M

100% 的数据保证 1≤n≤10000

#include<iostream>
#include<queue>
using namespace std;

int main() {
    priority_queue<int, vector<int>, greater<int> > que;//优先队列小顶堆
    int n, ans = 0;
    cin >> n;
    for (int i = 0; i < n; i++) {
        int t;
        cin >> t;
        que.push(t);
    }
    while(que.size() != 1) {//个数不为1时,持续合并
        int t = que.top();//最小的
        que.pop();
        t += que.top();
        que.pop();
        que.push(t); //合并的元素添加进去,自动排序成为小顶堆
        ans += t;
    }
    cout << ans << endl;

    return 0;
}

7、oj-573桐桐的新闻系统(优先队列)

题目描述

桐桐为期末的计算机作业设计了一套新闻系统,他把这套新闻系统称为 Argus。使用这套系统的用户可以向这套系统注册,然后这套系统就会以用户要求发送新闻的时间间隔向用户发送一次新闻。

向 Argus 注册的指令具有这样的格式:RegisterQnum Period

Qnum($0

所有的用户都有不同的 Qnum桐桐测试了一段时间后,想知道系统前 K 次给谁发送新闻了。如果同一时间发送多个新闻,以 Qnum 的升序排列。

输入

第一部分是注册指令,每条一行。指令数不超过 1000。此部分以 ““ # ”” 结束。

第二部分仅一行一个整数 K,K≤10000。

输出

输出前 K 个新闻发送到的用户的 Qnum,每行一个。

样例输入

Register 2004 200
Register 2005 300
#
5

样例输出

2004
2005
2004
2004
2005

规模与约定

时间限制:11 s

内存限制:256256 M

#include<iostream>
#include<queue>
#include<string>
using namespace std;

struct node {
    int id, num, next;
    bool operator< (const node &b) const {//默认是大根堆,重载小于号时要返过来
        if(this->next == b.next) {
            return this->id > b.id;
        } 
        return this->next > b.next;
    }
};

priority_queue<node> que;
int main() {
   string t;
    while(cin >> t) {
        if(t == "#") {
            break;
        }
        int id, num, next;
        cin >> id >> num;
        next = num;
        que.push((node){id, num, next});
    }
    int n;
    cin >> n;
    for (int i = 0; i < n; i++) {
        node temp = que.top();
        que.pop();
        cout << temp.id << endl;
        temp.next += temp.num;
        que.push(temp);
    }
    return 0;
}

8、oj-382报数

题目描述

N 个人围成一圈,编号分别为 1,2,3……N,第一个人从 1 报数,按照编号顺序依次报数,报 M 的人会离开队伍,然后下一个人会继续从 1 开始报数,直到剩下一人,剩下的人的编号是多少?

输入

共一行两个数 N 和 M。

输出

输出一个数表示最后一人的编号。

样例输入

7 3

样例输出

4

数据规模与约定

时间限制:1 s

内存限制:256 M

100% 的数据保证 1≤N,M≤1000

#include<iostream>
#include<queue>
using namespace std;

int main() {
    int n, m;
    int num = 0;
    queue<int> que;
    cin >> n >> m;
    for (int i = 1; i <= n;i++) {
        que.push(i);
    }
    while(que.size() != 1) {
        num++;
        if(num == m) {
            que.pop();
            num = 0;
            continue;
        } else {
            int temp = que.front();
            que.pop();
            que.push(temp);
        }
    }
    cout << que.front() << endl;


    return 0;
}

9、oj-377字符串匹配

题目描述

给出一个字符串,判断其中的左右圆括号是否匹配。

注:只需判断左右圆括号 ′(′ ′(′ 和 ′)′ ′)′。

输入

一行一个字符串,以字符@为结尾。

输出

若匹配,输出 YESYES,若不匹配,则输出 NONO。

样例输入

a(cc())bbb()@

样例输出

YES

样例输入2

a(cc()bbb()@

样例输出2

NO

数据规模与约定

时间限制:1 s

内存限制:256 M

100% 的数据保证 字符串长度小于 300

#include<iostream>
#include<stack>
using namespace std;

int main() {
    char s[305];
    stack<char> sta;
    cin >> s;
    for (int i = 0; s[i]; i++) {
        if(s[i] == '(') {
            sta.push(s[i]);
        } else if(s[i] == ')') {
            if(sta.empty()) {
                cout << "NO" << endl;
                return 0;
            }
            sta.pop();
        }
    }
    if(sta.empty()) {
        cout << "YES" << endl;
    } else {
        cout << "NO" << endl;
    }
    return 0;
}

10、oj-378字符串匹配2

题目描述

给出一个字符串,判断其中的左右括号是否匹配。

:需同时判断左右圆括号 ′(′ 和 ′)′,左右中括号 ′[′ 和 ′]′,左右大括号 ′{′和 ′}′。

不需要考虑括号之间的优先级的问题,也就是说,小括号包含大括号,也是被允许的。

输入

一行一个字符串,以字符@为结尾。

输出

若匹配,输出 YES,若不匹配,则输出 NO。

样例输入

a(cc[])bbb()@

样例输出

YES

样例输入2

a(cc[)]bbb()@

样例输出2

NO

数据规模与约定

时间限制:1 s

内存限制:256 M

100% 的数据保证 字符串长度小于 300

#include<iostream>
#include<stack>
using namespace std;

int main() {
    char str[305];
    cin >> str;
    stack<char> sta;
    for (int i =  0;str[i]; i++) {
        if (str[i] == '(' || str[i] == '[' || str[i] == '{') {
            sta.push(str[i]);
        } else if (str[i] == ')') {
            if(!sta.empty() && sta.top() == '(') {
                sta.pop();
            } else {
                cout << "NO" << endl;
                return 0;
            }
        } else if(str[i] == ']') {
                if (!sta.empty() && sta.top() == '[') {
                    sta.pop();
                } else {
                    cout << "NO" << endl;
                    return 0;
                }
        } else if(str[i] == '}') {
            if(!sta.empty() && sta.top() == '{') {
                sta.pop();
            } else {
                cout << "NO" << endl;
                return 0;
            }
        }
    }
    if (sta.empty()) cout << "YES" << endl;
    else cout << "NO" << endl;

    return 0;
}

11、oj-383周末舞会

题目描述

假设在周末舞会上,X名男士和 Y 名女士进入舞厅时,各自排成一队,并分别按顺序编号。跳舞开始时,依次从男队和女队的队头上各出一人配成舞伴。规定每个舞曲只能有一对跳舞者。跳完舞的人回到队尾。输出前 NN 首舞曲的跳舞者编号。

输入

一行三个数 X,Y,N。

输出

输出共 N 行,一行两个数,分别代表跳这支舞曲的男士编号和女士编号,两数之间用空格隔开。

样例输入

3 5 6

样例输出

1 1
2 2
3 3
1 4
2 5
3 1

数据规模与约定

时间限制:1 s

内存限制:256 M

100% 的数据保证 1≤N,M,X≤1000

#include<iostream>
#include<queue>
using namespace std;


int main() {
    int x, y, n;
    cin >> x >> y >> n;
    queue<int> m, w;
    for (int i = 1; i <= x; i++){
        m.push(i);
    }
    for (int i = 1; i <= y; i++) {
        w.push(i);
    }
    for (int i = 1; i <= n; i++) {
        cout << m.front() << " " << w.front() << endl;
        m.push(m.front());
        w.push(w.front());
        m.pop();
        w.pop();
    }
    return 0;
}

12、oj-384敲七

题目描述

有 N 个人在玩一种“敲7”游戏,游戏的规则是这样的:第 x 个人从 t 开始报数,然后按顺序报数,当某人报的数是 7 的倍数或数字中含有 7 时,便被淘汰,剩下的人继续报数,直到只剩下一个人。现求最终剩下的人编号?

输入

一行三个数 N,x,t。

输出

共一行一个数表示最终剩下的人的编号。

样例输入

4 3 6

样例输出

3

数据规模与约定

时间限制:1 s

内存限制:256 M

100% 的数据保证 1≤N,x,t≤1000

#include<iostream>
#include<queue>
using namespace std;

int func(int x) {
    if (x % 7 == 0) {
        return 1;
    }
    while (x) {
        if (x % 10 == 7) {
            return 1;
        }
        x /= 10;
    }
    return 0;
}

int main() {
    int n, x, t;
    cin >> n >> x >> t;
    queue<int> que;
    for (int i = x; i <= n; i++) {
        que.push(i);
    } 
    for (int i = 1; i < x; i++) {
        que.push(i);
    }
    while(que.size() != 1) {
        if (func(t) == 1) {
            que.pop();
        } else {
            que.push(que.front());
            que.pop();
        }
        t++;
    }
    cout << que.front() << endl;

    return 0;
}

13.OJ-575查字典

题目描述

小明正在复习全国英语四级考试,他手里有一本词典,现在有很多单词要查。请编写程序帮助他快速找到要查的单词所在的页码。

输入

第 1 行 1个正整数 N,N≤10000,表示字典中一共有多少单词。

接下来每两行表示一个单词,其中:

第 1行是一个长度小于或等于 100的字符串,表示这个单词,全部小写字母,单词不会重复。

第 2行是 1 个整数,表示这个单词在字典中的页码。

接下来的一行是 11 个整数 M,M≤10000,表示要查的单词数。

接下来的 M行,每行一个字符串,表示要查的单词,保证在字典中存在。

输出

M 行,每行一个正整数,表示第 i个单词在字典中的页码。

样例输入

2
scan
10
word
15
2
scan
word

样例输出

10
15

数据规模与约定

时间限制:11 s

内存限制:128128 M

#include<iostream>
#include<map>
#include<string>
using namespace std;


int main() {
    int n, cnt;
    map<string, int> m;
    cin >> n;
    for (int i = 0; i < n; i++) {
        string t;
        int tt;
        cin >> t >> tt;
        m[t] = tt;
        //或者m.insert(make_pair(t, tt)); --> 头文件 <utility>
    }
    cin >> cnt;
    for (int i = 0; i < cnt; i++) {
        string s;
        cin >> s;
        cout << m[s] << endl;
    }

    return 0;
}

14、oj-577讲话模式

题目描述

每个人讲话都有口头禅。现在给出一个字符串,需要求出其中出现次数最多的单词。

输入

输入一行,若干个长度小于或等于 10 的只包含大小写字母的字符串。

输出

输出一行,为出现次数最多的单词和它出现的次数,以一个空格隔开。

如果出现次数最多的单词有多个,则输出字典序最小的那个。这个单词必须完全以小写的形式输出。注意,所说的单词不区分大小写字母。

样例输入

Can a can can a can It can

样例输出

can 5

数据规模与约定

时间限制:1 s

内存限制:32 M

#include<iostream>
#include<map>
#include <string>
using namespace std;



int main() {
    map<string, int> m;
    string s, ans;
    int ans_cnt = 0;
    while(cin >> s) {
        for (int i = 0; i < s.size(); i++) {
            if (s[i] >= 'A' && s[i] <= 'Z') {
                s[i] += 'a' - 'A';
            }
        }
        m[s] = m[s] + 1;
        if (m[s] > ans_cnt) {
            ans = s;
            ans_cnt = m[s];
        }
        if (ans_cnt == m[s]) {
            ans = min(ans, s);//输出字典序小的
        }
    }
    cout << ans << " " << ans_cnt << endl;

    return 0;
}

写于2021-07-17

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值