这周是上ACM课的第一周,主要讲的是计算机竞赛基本事项和标准模版库(STL)以及贪心算法。
文章分为两大部分,一部分是这周的知识总结,另一部分是这一走的心得。
索引
一、知识总结部分
一、ACM基本加速写代码常识
万能头文件:bits/stdc++.h
。只包含此头文件便可代替大部分C++自带头文件。
cin加速器:cin在接受大量数据时会变得缓慢,不如scanf。但scanf写起来太麻烦,这时在main函数把这段代码作为第一句:
ios::sync_with_stdio(false);
便可以解决这个问题。
宏定义:有时经常出现的代码会占用大量时间去输入,这时使用宏定义即可大大减少所用时间。比如
for (int i = 0; i < 0; i ++)
在文件中使用以下代码:
#define rep(i, a, n) for(int i = a; i < n; i++)
下次在使用相同结构只需要这样如:
rep(i, 0, 3) cout << “ha”;
输出为:hahaha
。
typedef
:和宏定义一样,其目的是减少敲代码的时间,例如:
typedef long long ll;
下次用
long long a
只需写成ll a
;
此后用到的区间多为[a, b)
类型(同Python)。
二、C++中的STL
I.容器对象
注:.size()
/ .upper_bound()
/ lower_bound()
等算作一般操作,除特殊情况外,不出现在特殊操作
标签下。
1.string
(1)
string line;
getline(cin, line)
可将空格传到字符串变量line
中。这里的cin
指从键盘读入数据,可替换以从文件读入数据。注意这段代码不能存储回车;
(2)s.empty();
用来判断是否是空字符串。空返回1,非空返回0;
2.栈
定义方法:
stack <type> name
特殊操作:
.pop()
移除栈顶元素;
.top()
返回栈顶元素;
.push([type] a)
向栈压入一个元素a;
3.队列
定义方法:
queue <type> name
特殊操作:
.front()
返回queue内的下一个元素;
.back()
返回queue内的最后一个元素;
.pop()
移除queue中的一个元素
.push([type] a)
向queue置入一个元素a;
4.动态数组
定义方法:
vector <type> a
特殊操作:
.push_back([type] a)
将元素a插入最尾端
.pop_back()
将最尾端元素删除
5.优先队列
优先队列会把权值最高的先弹出。这叫堆。
头文件:queue
定义方法:
priority_queue <type> name
如:priority_queue <int> a; //默认是大顶堆
操作同string和vector等。
6.set 和 multiset
set 和 multiset 会根据特定的排序准则,自动将元素排序,其中 set 不允许重复元素出现,multiset 允许。
头文件:set
定义方法:
set <type> name;
multiset <type> name;
//默认由小到大排列
如果想按照自己的方式排序,可以使用运算符重载
重载小于号:
bool operator < (const type &a)const{
if(x != a.x) return x < a.x;
return y < a.y;
}
set 和 multiset 特殊应用:
s.count(elem)
— 返回元素值为elem的元素的个数
s.insert(elem)
— 安插一个elem副本,返回新元素的位置
s.erase(elem)
— 移除与elem元素相等的所有元素,返回被移除元素的个数。
s.erase(pos)
— 移除迭代器
pos所指位置上的元素,无返回值
以上位置均为一个迭代器。
s.begin()
— 返回一个双向迭代器,位置指向最后一个元素
s.end()
— 返回一个双向迭代器,位置只想最后一个元素
s.clear()
— 清除全部元素
迭代器举例:
...
multiset <int> :: iterator pos;
for(pos = s.begin(); pos != s.end(); pos++)
...
7. map 和 multimap
头文件:map
定义:
map <type_1, type_2> name;
//某人从小到大排序( string 类型亦是如此)
特殊操组:
m.count(key)
— 返回键值等于 key 的元素的个数
m.erase(elem)
— 移除键值为elem的所有元素,返回个数,对于 map 来说非 0 即 1
m.erase(pos)
— 移除迭代器
pos所指位置上的元素,直接元素存取
m[key] = value
— 查找是如果没有键值为key的元素,则安插一个键值为key的新元素,实值为默认(一般为0)
插入操作:
m.insert(elem);
//一般方式
map <string, float> m;
m.insert(map<string, float>::value_type (“Robin”, 22.3));
//运用 value_type 插入
m.insert(pair<string, float>(“Robin”, 22.3));
//运用 pair<> 插入
m.insert(make_pair(“Robin”, 22.3));
//运用make_pair()
(其他同 set / multiset 和其他类型容器)
II.函数
1.sort
函数用法:
sort(begin, end, [cmp])
begin
和 end
都是数组或其他排列的地址。cmp
为布尔值类型的函数,0时为倒置相邻元素,1时为不倒置相邻元素。
cmp的使用:
定义:
bool cmp(type a, type b){
return rule;
}
比如有一个int类型的数组a,现要对其由小到大排序:
bool cmp(int a, int b){
return (a < b); //换成a > b就是由大到小排列
}
2.去重uniqe
函数作用是“去除”容器或数组 相邻 元素重复出现的元素。
这里只是把重复元素放到容器的尾部,并不是真的“去除”,返回值是去重之后的尾地址。
常常配合sort函数出现。
这里介绍个名词叫迭代器(iterator):
iterator unique(iterator begin, iterator);
iterator unique(iterator begin, iterator end, bool MyFunc);
参数列表中前两个参数都是迭代器,表示对区间 [ it_1, it_2 ) 内进行去重(注意左闭右开)。
最后一个参数是元素是否相等的判断函数(类似sort)。
返回值是指向最后一个元素的下一个元素的迭代器。
迭代器:又称光标,老师说就是一个指针,可在容器对象上遍访的接口。迭代,就是重复执行一些事。
3.生成排列
头文件:algorithm
定义方法:
bool next_permutation(begin, end);
改变区间内元素的位置,产生下一个排列。
bool prev_permutation(begin, end);
产生前一个排列。
4.upper_bound 和 lower_bound
upper_bound(begin, end, value);
//返回 >value 的元素的第一个位置
lower_bound(begin, end, value);
//返回 >=value 的元素的第一个位置
III.贪心算法
概述
核心决策:按照最优策略
将复杂问题层层分解成子问题问题(每次一般只有一个),并由子策略回溯
出整个问题的最优解
策略判断:不是从整体考虑问题,只在某种意义上的局部最优解(“贪心”之意);
通常是最好的解决问题的办法。
解题原则
打算运用贪心算法之前,需要思考两个问题:
(1)该问题是否适合用贪心算法;
(2)如何选择贪心准则以得到最优解。
贪心算法常见权重方法:
性价比
:比如存在两个条件,重量
和价值
,但重量不允许过载,此时用价值/重量
的性价比权重法。
二.心得部分
这是我第一次接触ACM课程。从这几天的学习中,我体会到前所未有的困难。于是,我从各个方面分析了对待这些困难的方法。
学习方面:
严格要求自己,保持认真的科学研究态度,把每一种问题吃透,才能真正取得进步。
心态方面:
不急不躁,冷静对待问题,仔细分析、认真思考。
处理问题方面
一定要尽自己之力,不到最后一刻绝不求人,同时积极参与问题探讨。