ACM竞赛常用STL(一)
全排列函数next_permutation
STL 中专门用于排列的函数(可以处理存在重复数据集的排列问题)
头文件:#include <algorithm>
using namespace std;
调用: next_permutation(start, end);
注意:函数要求输入的是一个升序排列的序列的头指针和尾指针.
用法:
- // 数组
- int a[N];
- sort(a, a+N);
- next_permutation(a, a+N);
- // 向量
- vector<int> ivec;
- sort(ivec.begin(), ivec.end());
- next_permutation(ivec.begin(), ivec.end());
- 例子:
- vector<int> myVec;
- // 初始化代码
- sort(myVec.begin(),myVec.end());
- do{
- for (i = ;i < size;i ++ ) cout << myVec[i] << " \t " ;
- cout << endl;
- }while (next_permutation(myVec.begin(), myVec.end()));
ACM/ICPC 竞赛之STL--pair
STL 的<utility>头文件中描述了一个看上去非常简单的模板类pair,用来表示一个二元组或元素对,并提供了按照字典序对元素对进行大小比较的比较运算符模板函数。
例如,想要定义一个对象表示一个平面坐标点,则可以:
pair<double, double> p1;cin >> p1.first >> p1.second;pair 模板类需要两个参数:首元素的数据类型和尾元素的数据类型。pair 模板类对象有两个成员:first 和second,分别表示首元素和尾元素。
在<utility>中已经定义了pair 上的六个比较运算符:<、>、<=、>=、==、!=,其规则是先比较first,first 相等时再比较second,这符合大多数应用的逻辑。当然,也可以通过重载这几个运算符来重新指定自己的比较逻辑。除了直接定义一个pair 对象外,如果需要即时生成一个pair 对象,也可以调用在<utility>中定义的一个模板函数:make_pair。make_pair 需要两个参数,分别为元素对的首元素和尾元素。
在题1067--Ugly Numbers 中,就可以用pair 来表示推演树上的结点,用first 表示结点的值,用second 表示结点是由父结点乘以哪一个因子得到的。
- #include <iostream>
- #include <queue>
- using namespace std;
- typedef pair<unsigned long, int> node_type;
- int main()
- {
- unsigned long result[];
- priority_queue< node_type, vector<node_type>,
- greater<node_type> > Q;
- Q.push( make_pair(, ) );
- for (int i=; i<; i++)
- {
- node_type node = Q.top(); Q.pop();
- switch(node.second)
- {
- case : Q.push( make_pair(node.first*, ) );
- case : Q.push( make_pair(node.first*, ) );
- case : Q.push( make_pair(node.first*, ) );
- }
- result[i] = node.first;
- }
- int n;
- cin >> n;
- while (n>)
- {
- cout << result[n-] << endl;
- cin >> n;
- }
- return ;
- }
ACM/ICPC 竞赛之STL--vector
在STL 的<vector>头文件中定义了vector(向量容器模板类),vector容器以连续数组的方式存储元素序列,可以将vector 看作是以顺序结构实现的线性表。当我们在程序中需要使用动态数组时,vector 将会是理想的选择,vector 可以在使用过程中动态地增长存储空间。
vector 模板类需要两个模板参数,第一个参数是存储元素的数据类型,第二个参数是存储分配器的类型,其中第二个参数是可选的,如果不给出第二个参数,将使用默认的分配器。
下面给出几个常用的定义vector 向量对象的方法示例:38
vector<int> s;
定义一个空的vector 对象,存储的是int 类型的元素。
vector<int> s(n);定义一个含有n 个int 元素的vector 对象。
vector<int> s(first, last);定义一个vector 对象,并从由迭代器first 和last 定义的序列[first,last)中复制初值。
vector 的基本操作有:
s[i]直接以下标方式访问容器中的元素。
s.front() 返回首元素。
s.back() 返回尾元素。
s.push_back(x)向表尾插入元素x。
s.size() 返回表长。
s.empty() 当表空时,返回真,否则返回假。
s.pop_back() 删除表尾元素。
s.begin() 返回指向首元素的随机存取迭代器。
s.end() 返回指向尾元素的下一个位置的随机存取迭代器。
s.insert(it, x) 向迭代器it 指向的元素前插入新元素val。
s.insert(it, n, x)向迭代器it 指向的元素前插入n 个x。
s.insert(it, first, last)将由迭代器first 和last 所指定的序列[first, last)插入到迭代器it
指向的元素前面。
s.erase(it)删除由迭代器it 所指向的元素。
s.erase(first, last)删除由迭代器first 和last 所指定的序列[first, last)。
s.reserve(n)预分配缓冲空间,使存储空间至少可容纳n 个元素。
s.resize(n)改变序列的长度,超出的元素将会被删除,如果序列需要扩展(原空间小于n),元素默认值将填满扩展出的空间。
s.resize(n, val)改变序列的长度,超出的元素将会被删除,如果序列需要扩展(原空间小于n),将用val 填满扩展出的空间。
s.clear()删除容器中的所有的元素。
s.swap(v)将s 与另一个vector 对象v 进行交换。
s.assign(first, last)将序列替换成由迭代器first 和last 所指定的序列[first, last)。[first, last)不能是原序列中的一部分。要注意的是,resize 操作和clear 操作都是对表的有效元素进行的操作,但并不一定会改变缓冲空间的大小。另外,vector 还有其他一些操作如反转、取反等,不再一下列举。vector 上还定义了序列之间的比较操作运算符(>, <, >=, <=, ==, !=),
可以按照字典序比较两个序列。还是来看一些示例代码。输入个数不定的一组整数,再将这组整数按倒序输出,
如下所示:
- #include <iostream>
- #include <vector>
- using namespace std;
- int main()
- {
- vector<int> L;
- int x;
- while (cin>>x) L.push_back(x);
- for (int i=L.size()-; i>=; i--)
- cout << L[i] << " ";
- cout << endl;
- return ;
- }
ACM/ICPC 竞赛之STL--iterator 简介
iterator(迭代器)是用于访问容器中元素的指示器,从这个意义上说,iterator(迭代器)相当于数据结构中所说的“遍历指针”,也可以把iterator(迭代器)看作是一种泛化的指针。STL 中关于iterator(迭代器)的实现是相当复杂的,这里我们暂时不去详细讨论关于iterator(迭代器)的实现和使用,而只对iterator(迭代器)做一点简单的介绍。
简单地说,STL 中有以下几类iterator(迭代器):
输入iterator(迭代器),在容器的连续区间内向前移动,可以读取容器内任意值;输出iterator(迭代器),把值写进它所指向的容器中;前向iterator(迭代器),读取队列中的值,并可以向前移动到下一位置(++p,p++);双向iterator(迭代器),读取队列中的值,并可以向前向后遍历容器;随机访问iterator(迭代器), 可以直接以下标方式对容器进行访问,vector 的iterator(迭代器)就是这种iterator(迭代器);流iterator(迭代器),可以直接输出、输入流中的值;每种STL 容器都有自己的iterator(迭代器)子类,下面先来看一段简单的示例代码:
- #include <iostream>
- #include <vector>
- using namespace std;
- main()
- {
- vector<int> s;
- for (int i=; i<; i++)
- s.push_back(i);
- for (vector<int>::iterator it=s.begin(); it!=s.end();it++)
- cout << *it << " ";
- cout << endl;
- return ;
- }
vector 的begin()和end()方法都会返回一个vector::iterator 对象,分别指向vector 的首元素位置和尾元素的下一个位置(我们可以称之为结束标志位置)。对一个iterator(迭代器)对象的使用与一个指针变量的使用极为相似,或者可以这样说,指针就是一个非常标准的iterator(迭代器)。再来看一段稍微特别一点的代码:
- #include <iostream>
- #include <vector>
- using namespace std;
- main()
- {
- vector<int> s;
- s.push_back();
- s.push_back();
- s.push_back();
- copy(s.begin(), s.end(), ostream_iterator<int>(cout, ""));
- cout <<endl;
- return ;
- }
这段代码中的copy 就是STL 中定义的一个模板函数,copy(s.begin(),s.end(), ostream_iterator<int>(cout, " "));的意思是将由s.begin()至s.end()(不含s.end())所指定的序列复制到标准输出流cout 中,用" "作为每个元素的间隔。也就是说,这句话的作用其实就是将表中的所有内容依次输出。iterator(迭代器)是STL 容器和算法之间的“胶合剂”,几乎所有的STL 算法都是通过容器的iterator(迭代器)来访问容器内容的。只有通过有效地运用iterator(迭代器),才能够有效地运用STL 强大的算法功能。
ACM/ICPC 竞赛之STL--string
字符串是程序中经常要表达和处理的数据,我们通常是采用字符数组或字符指针来表示字符串。STL 为我们提供了另一种使用起来更为便捷的字符串的表达方式:string。string 类的定义在头文件<string>中。string 类其实可以看作是一个字符的vector,vector 上的各种操作都可以适用于string,另外,string 类对象还支持字符串的拼合、转换等操作。下面先来看一个简单的例子:
- #include <iostream>
- #include <string>
- using namespace std;
- int main()
- {
- string s = "Hello! ", name;
- cin >> name;
- s += name;
- s += '!';
- cout << s << endl;
- return ;
- }
再以题1064--Parencoding 为例,看一段用string 作为容器,实现由P
代码还原括号字符串的示例代码片段:
- int m;
- cin >> m; // P 编码的长度
- string str; // 用来存放还原出来的括号字符串
- int leftpa = ; // 记录已出现的左括号的总数
- for (int j=; j<m; j++)
- {
- int p;
- cin >> p;
- for (int k=; k<p-leftpa; k++) str += '(';
- str += ')';
- leftpa = p;
- }
ACM/ICPC 竞赛之STL--stack/queue
stack(栈)和queue(队列)也是在程序设计中经常会用到的数据容器,STL为我们提供了方便的stack(栈)的queue(队列)的实现。39准确地说,STL 中的stack 和queue 不同于vector、list 等容器,而是对这些容器的重新包装。这里我们不去深入讨论STL 的stack 和queue 的实现细节,而是来了解一些他们的基本使用。
1、stack
stack 模板类的定义在<stack>头文件中。
stack 模板类需要两个模板参数,一个是元素类型,一个容器类型,但只有元
素类型是必要的,在不指定容器类型时,默认的容器类型为deque。
定义stack 对象的示例代码如下:
stack<int> s1;
stack<string> s2;
stack 的基本操作有:
入栈,如例:s.push(x);
出栈,如例:s.pop();注意,出栈操作只是删除栈顶元素,并不返回该元素。
访问栈顶,如例:s.top()
判断栈空,如例:s.empty(),当栈空时,返回true。
访问栈中的元素个数,如例:s.size()
下面是用string 和stack 写的解题1064--Parencoding 的程序。
- #include <iostream>
- #include <string>
- #include <stack>
- using namespace std;
- int main()
- {
- int n;
- cin >> n;
- for (int i=; i<n; i++)
- {
- int m;
- cin >> m;
- string str;
- int leftpa = ;
- for (int j=; j<m; j++) // 读入P 编码,构造括号字符串
- {
- int p;
- cin >> p;
- for (int k=; k<p-leftpa; k++)
- str += '(';
- str += ')';
- leftpa = p;
- }
- stack<int> s;
- for (string::iterator it=str.begin();it!=str.end(); it++)
- { // 构造M 编码
- if (*it=='(') s.push();
- else
- {
- int p = s.top(); s.pop();
- cout << p << " ";
- if (!s.empty()) s.top() += p;
- }
- }
- cout << endl;
- }
- return ;
- }
2、queue
queue 模板类的定义在<queue>头文件中。stack 模板类很相似,queue 模板类也需要两个模板参数,一个是元素类型,一个容器类型,元素类型是必要的,容器类型是可选的,默认为deque 类型。
定义queue 对象的示例代码如下:
queue<int> q1;
queue<double> q2;
queue 的基本操作有:
入队,如例:q.push(x); 将x 接到队列的末端。
出队,如例:q.pop(); 弹出队列的第一个元素,注意,并不会返回被弹出元素的值。
访问队首元素,如例:q.front(),即最早被压入队列的元素。
访问队尾元素,如例:q.back(),即最后被压入队列的元素。
判断队列空,如例:q.empty(),当队列空时,返回true。
访问队列中的元素个数,如例:q.size()
3、priority_queue
在<queue>头文件中,还定义了另一个非常有用的模板类priority_queue(优先队列)。优先队列与队列的差别在于优先队列不是按照入队的顺序出队,而是按照队列中元素的优先权顺序出队(默认为大者优先,也可以通过指定算子来指定自己的优先顺序)。priority_queue 模板类有三个模板参数,第一个是元素类型,第二个容器类型,第三个是比较算子。其中后两个都可以省略,默认容器为vector,默认算子为less,即小的往前排,大的往后排(出队时序列尾的元素出队)。
定义priority_queue 对象的示例代码如下:
priority_queue<int> q1;
priority_queue< pair<int, int> > q2; // 注意在两个尖括号之间一定要留空格。
priority_queue<int, vector<int>, greater<int> > q3; // 定义小的先出队
priority_queue 的基本操作与queue 相同。
初学者在使用priority_queue 时,最困难的可能就是如何定义比较算子了。如果是基本数据类型,或已定义了比较运算符的类,可以直接用STL 的less算子和greater 算子——默认为使用less 算子,即小的往前排,大的先出队。如果要定义自己的比较算子,方法有多种,这里介绍其中的一种:重载比较运算符。优先队列试图将两个元素x 和y 代入比较运算符(对less 算子,调用x<y,对greater 算子,调用x>y),若结果为真,则x 排在y 前面,y 将先于x 出队,反之,则将y 排在x 前面,x 将先出队。
看下面这个简单的示例:
- #include <iostream>
- #include <queue>
- using namespace std;
- class T
- {
- public:
- int x, y, z;
- T(int a, int b, int c):x(a), y(b), z(c){}
- };
- bool operator < (const T &t1, const T &t2)
- {
- return t1.z < t2.z; // 按照z 的顺序来决定t1 和t2 的顺序
- }
- int main()
- {
- priority_queue<T> q;
- q.push(T(,,));
- q.push(T(,,));
- q.push(T(,,));
- q.push(T(,,));
- while (!q.empty())
- {
- T t = q.top(); q.pop();
- cout << t.x << " " << t.y << " " << t.z << endl;
- }
- return ;
- }
- /*输出结果为(注意是按照z 的顺序从大到小出队的):
- 3 3 6
- 2 2 5
- 1 5 4
- 4 4 3*/
- //再看一个按照z 的顺序从小到大出队的例子:
- #include <iostream>
- #include <queue>
- using namespace std;
- class T
- {
- public:
- int x, y, z;
- T(int a, int b, int c):x(a), y(b), z(c)
- {
- }
- };
- bool operator > (const T &t1, const T &t2)
- {
- return t1.z > t2.z;
- }
- int main()
- {
- priority_queue<T, vector<T>, greater<T> > q;
- q.push(T(,,));
- q.push(T(,,));
- q.push(T(,,));
- q.push(T(,,));
- while (!q.empty())
- {
- T t = q.top(); q.pop();
- cout << t.x << " " << t.y << " " << t.z << endl;
- }
- return ;
- }
输出结果为:
4 4 3
1 5 4
2 2 5
3 3 6
如果我们把第一个例子中的比较运算符重载为:
bool operator < (const T &t1, const T &t2){
return t1.z > t2.z; // 按照z 的顺序来决定t1 和t2 的顺序
}
则第一个例子的程序会得到和第二个例子的程序相同的输出结果。
再回顾一下用优先队列实现的题1067--Ugly Numbers 的代码:
- #include <iostream>
- #include <queue>
- using namespace std;
- typedef pair<unsigned long int, int> node_type;
- int main( int argc, char *argv[] )
- {
- unsigned long int result[];
- priority_queue< node_type, vector<node_type>,
- greater<node_type> > Q;
- Q.push( make_pair(, ) );
- for (int i=; i<; i++)
- {
- node_type node = Q.top();
- Q.pop();
- switch(node.second)
- {
- case : Q.push( make_pair(node.first*, ) );
- case : Q.push( make_pair(node.first*, ) );
- case : Q.push( make_pair(node.first*, ) );
- }
- result[i] = node.first;
- }
- int n;
- cin >> n;
- while (n>)
- {
- cout << result[n-] << endl;
- cin >> n;
- }
- return ;
- }
ACM/ICPC 竞赛之STL--map
在STL 的头文件<map>中定义了模板类map 和multimap,用有序二叉树来存贮类型为pair<const Key, T>的元素对序列。序列中的元素以const Key部分作为标识,map 中所有元素的Key 值都必须是唯一的,multimap 则允许有重复的Key 值。可以将map 看作是由Key 标识元素的元素集合,这类容器也被称为“关联容器”,可以通过一个Key 值来快速确定一个元素,因此非常适合于需要按照Key值查找元素的容器。map 模板类需要四个模板参数,第一个是键值类型,第二个是元素类型,第三个是比较算子,第四个是分配器类型。其中键值类型和元素类型是必要的。map 的基本操作有:
1、定义map 对象,例如:
map<string, int> m;
2、向map 中插入元素对,有多种方法,例如:
m[key] = value;
[key]操作是map 很有特色的操作,如果在map 中存在键值为key 的元素对,
则返回该元素对的值域部分,否则将会创建一个键值为key 的元素对,值域为默认值。所以可以用该操作向map 中插入元素对或修改已经存在的元素对的值域部分。
m.insert( make_pair(key, value) );
也可以直接调用insert 方法插入元素对,insert 操作会返回一个pair,当map 中没有与key 相匹配的键值时,其first 是指向插入元素对的迭代器,其second 为true;若map 中已经存在与key 相等的键值时,其first 是指向该元素对的迭代器,second 为false。
3、查找元素对,例如:
int i = m[key];
要注意的是,当与该键值相匹配的元素对不存在时,会创建键值为key 的元素对。map<string, int>::iterator it = m.find(key);如果map 中存在与key 相匹配的键值时,find 操作将返回指向该元素对的迭代器,否则,返回的迭代器等于map 的end()(参见vector 中提到的begin
和end 操作)。
4、删除元素对,例如:
m.erase(key);删除与指定key 键值相匹配的元素对,并返回被删除的元素的个数。
m.erase(it);删除由迭代器it 所指定的元素对,并返回指向下一个元素对的迭代器。
看一段简单的示例代码:
- #include<map>
- #include<iostream>
- using namespace std;
- typedef map<int, string, less<int> > M_TYPE;
- typedef M_TYPE::iterator M_IT;
- typedef M_TYPE::const_iterator M_CIT;
- int main()
- {
- M_TYPE MyTestMap;
- MyTestMap[] = "No.3";
- MyTestMap[] = "No.5";
- MyTestMap[] = "No.1";
- MyTestMap[] = "No.2";
- MyTestMap[] = "No.4";
- M_IT it_stop = MyTestMap.find();
- cout << "MyTestMap[2] = " << it_stop->second << endl;
- it_stop->second = "No.2 After modification";
- cout << "MyTestMap[2] = " << it_stop->second << endl;
- cout << "Map contents : " << endl;
- for(M_CIT it = MyTestMap.begin(); it != MyTestMap.end();it++)
- {
- cout << it->second << endl;
- }
- return ;
- }
- /*程序执行的输出结果为:
- MyTestMap[2] = No.2
- MyTestMap[2] = No.2 After modification
- Map contents :
- No.1
- No.2 After modification
- No.3
- No.4
- No.5*/
再看一段简单的示例代码:
- #include <iostream>
- #include <map>
- using namespace std;
- int main()
- {
- map<string, int> m;
- m["one"] = ;
- m["two"] = ;
- // 几种不同的insert 调用方法
- m.insert(make_pair("three", ));
- m.insert(map<string, int>::value_type("four", ));
- m.insert(pair<string, int>("five", ));
- string key;
- while (cin>>key)
- {
- map<string, int>::iterator it = m.find(key);
- if (it==m.end())
- {
- cout << "No such key!" << endl;
- }
- else
- {
- cout << key << " is " << it->second << endl;
- cout << "Erased " << m.erase(key) << endl;
- }
- }
- return ;
- }
ACM竞赛常用STL(一)的更多相关文章
- ACM竞赛常用STL(二)之STL--algorithm
<algorithm>无疑是STL 中最大的一个头文件,它是由一大堆模板函数组成的.下面列举出<algorithm>中的模板函数: adjacent_find / binary ...
- 竞赛常用STL备忘录
__builtin: __builtin_popcount:二进制中 1 的个数__builtin_ctz:末尾的 0,即对 lowbit 取log__builtin_clz:开头的 0,用 31 减 ...
- ACM竞赛常用头文件模板-备忘
备忘. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> ...
- ACM 中常用的算法有哪些? 2014-08-21 21:15 40人阅读 评论(0) 收藏
ACM 中常用的算法有哪些?作者: 张俊Michael 网络上流传的答案有很多,估计提问者也曾经去网上搜过.所以根据自己微薄的经验提点看法. 我ACM初期是训练编码能力,以水题为主(就是没有任何算法, ...
- ACM竞赛高手比其他程序员水平高很多吗?
1. ACM是一种很直接的评价程序员水平的体系 2. ACM竞赛会带来很多机遇(深造or工作),同时又是一个不小的挑战 3. 为竞赛而竞赛的事情不可取 详细点击这里
- 长安大学ACM竞赛部
本博客为长安大学ACM竞赛部的公共博客,记录长大ACMer的成长点滴. 开此博客,诸君共勉.
- C++常用STL
目录 C++ 常用STL整理 容器和配接器 list(链表) stack(栈) queue(队列) priority_queue(优先队列) set(集合) vector(向量) map&&a ...
- 常用STL使用指北
常用STL使用指北 set和multiset set和multiset都是基于红黑树(显然是一个二叉搜索树)的STL. 定义 我们可以使用(multi)set<元素类型>名称来定义一个(m ...
- C/C++解题常用STL大礼包 含vector,map,set,queue(含优先队列) ,stack的常用用法
每次忘记都去查,真难啊 /* C/C++解题常用STL大礼包 含vector,map,set,queue(含优先队列) ,stack的常用用法 */ /* vector常用用法 */ //头文件 #i ...
随机推荐
- linux —— shell 编程(文本处理)
导读 本文为博文linux —— shell 编程(整体框架与基础笔记)的第4小点的拓展.(本文所有语句的测试均在 Ubuntu 16.04 LTS 上进行) 目录 基本文本处理 流编辑器sed aw ...
- Cookie及App登陆的原理
1.Cookie Cookie意为"甜饼",是由W3C组织提出的.目前Cookie已经成为标准.由于HTTP是一种无状态的协议,服务器单从网络连接上无从知道客户身份.怎么办呢?就给 ...
- Qt 智能指针学习(7种指针)
Qt 智能指针学习 转载自:http://blog.csdn.net/dbzhang800/article/details/6403285 从内存泄露开始? 很简单的入门程序,应该比较熟悉吧 ^_^ ...
- Android RecyclerView使用(一)
RecyclerView一种可以替换掉listview gridview 瀑布流等控件的新视图控件,控制视图回收和复用 ==优化内存可以替换listview 与listview的不同之处是:listv ...
- 《31天成为IT服务达人》之精准运维
1 第十四章精准运维服务 近年来国内IT产业的发展格局始终与我国的经济转型与创新创业的社会大潮息息相关,纵观国内国际形势,IT产业仍是创新的领头者,是解决人类各种经济危机的主要扮演者 ...
- CSU1312:榜单(模拟)
Description ZZY很喜欢流行音乐,每周都要跟踪世界各地各种榜单,例如Oricon和Billboard,现在给出每周各个单曲的销量请给出每周的TOP5以及TOP5中各个单曲的浮动情况. 量的 ...
- TOJ3744(Transportation Costs)
Transportation Costs Time Limit(Common/Java):2000MS/6000MS Memory Limit:65536KByte Total Submi ...
- RGB的三维模型与渐变色-颜色系列之一
一.前言 以下与颜色相关的日志记录了俺学习颜色的有关容,限于编写时的水平,难免存在缺点与错误,希望得到朋友.同行和前辈的指教,非常感谢.1. RGB的三维模型与渐变色-颜色系列之一2. <颜 ...
- Map 迭代 两种方法
Map 迭代 两种方法 Map<String, String> map=new HashMap<String,String>(); map.put("1", ...
- ssh登录很慢解决方法
使用ssh客户端(如:putty)连接Linux服务器,可能会等待10-30秒才有提示输入密码.严重影响工作效率.登录很慢,登录上去后速度正常,这种情况主要有两种可能的原因: 1. DNS反向解析问题 ...