算法竞赛入门经典 c++与STL入门
本来我以为正式进入c++与STL可以晚一点,但经过这次校赛,我认为c++选手是真香。
1.1 引用
#include<iostream>
#include<algorithm>
using namespace std;
void swap2(int& a,int& b)
{
int t=a;
a=b;
b=t;
}
int main()
{
int a=3,b=4;
swap2(a,b);
cout<<a<<' '<<b<<endl;
return 0;
}
如果在参数前加一个‘&’符号,就表示这个参数按照传引用的方式传递,而不是c语言里的传值方式传递。这样,在函数内改变参数的值,也会修改道函数的实参。
又c++中的引用就是变量的“别名”,它可以在一定程度上代替c中的指针。
2.1 字符串
c++提供了一个新的string类型,用来代替c语言中的字符数组。如果希望程序更加简单,自然,string类型往往是更好的选择。
例如:c++的cin/cout可以直接读写string类型,却不能直接读写字符型数组:string类型还可以像整数那样相加,而c语言中只能使用strcat函数。
这里注释一下getline()函数:我们知道cin输入数据,当遇到空格,换行等会自行终止,那么如果要输入一行数据(包括空格)就要用getline函数。
getline函数可读取整行,包括前导和嵌入的空格,并将其存储在字符串对象中。
而getline函数的基础用法是:
#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
int main()
{
string c;
getline(cin,c);
cout<<c<<endl;
return 0;
}
这里还要注意,getline只适用于string类型,如果定义一个字符型数组,是不可以使用getline函数读取的。
2.2 stringstream 的用法
stringstream在sstream的头文件中,具体用法可以参考一下其他人写的博文,因为我也不太懂,就不在这里水了
https://blog.csdn.net/liitdar/article/details/82598039
还有就是一定要注意string很慢,sstream更慢,所以在竞赛中应该谨慎使用。
3.1 再谈结构体
呃呃呃呃,这个部分我是懵逼的,过段时间我去问了大佬学会来再回来补充
4.1 排序和检索
sort函数不用我多讲,已经是commonplace。
这里主要聊聊lower_bound函数的用法:
lower_bound函数主要是用于查找“大于或等于x的第一个位置”,如果配合着sort函数使用,在一定程度上可以简化代码。
再者使用lower_bound函数需要三个参数,第一个参数是数组的初始地址,第二个参数是数组的末尾位置,第三个参数是所要查找的元素值。
补充一下 lower_bound函数所需头文件是
5.1 不定长度数组:vector
vector是一个不定长数组。不仅如此,它把一些常用操作封装在了vector类型内部。
vector实际上就是一个动态数组,你输入多少数,它开辟多少空间
基于这个特点,在图论中,当数据达到1e5的时候,也就是当二维数组开辟不了这么多的时候,可以考虑用vector来处理。
若a是一个vector,则可以用a.size()读取它的大小,a.resize()改变大小,a.push_back()向尾部添加元素,a.pop_back()删除最后一个元素。
这里补充一点阴间东西,作为一个满脑子想加速的ACMER,如果手写a.pop_back无疑太慢且容易出错。所以为了提高编码效率,可以如下操作:
#define pub push_back
#define pob pop_back
a.pub(1);
a.pub(2);
a.pob();
很明显的这样写可以简便的多。
vector<int> 是一个类似于int a[]的整形数组
如果定义成vector<int>s[],就相当于定义了一个二维数组。
下面是木块问题的代码和我写的一些注解:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<string>
#include<vector>
using namespace std;
const int maxn = 30;
int n;
vector<int> pile[maxn];
//找到木块a所在的pile和height,以引用的形式返回调用者
void find_block(int a,int& p,int& h){
for(p=0;p<n;p++){
for(h=0;h<pile[p].size();h++){//a.size()用于读取大小
if(pile[p][h]==a) return ;//双重循环,一个遍历宽度,一个遍历高度。
}
}
}
//把第p堆高度为h的木块上方的所有木块移回原位
void clear_above(int p,int h){
for(int i=h+1;i<pile[p].size();i++){
int m=pile[p][i];//木块上方的木块为m
pile[m].push_back(m);//把m压入原来的位置
}
pile[p].resize(h+1);//保留h+1个元素,剩下的全部丢掉,这里注意因为第二维是从0开始的,所以保留h+1项
}
//把第p堆高度为h及其上方的木块整体移动到p2堆的顶部
void pile_onto(int p,int h,int p2){
for(int i=h;i<pile[p].size();i++)
pile[p2].push_back(pile[p][i]);
pile[p].resize(h);
}
void print()
{
for (int i = 0; i < n; i++)
{
printf("%d:", i);
for (int j = 0; j < pile[i].size(); j++)
printf(" %d", pile[i][j]);
printf("\n");
}
}
int main()
{
int a, b;
cin >> n;
string s1, s2;
for (int i = 0; i < n; i++)pile[i].push_back(i);//分别在第n堆压入元素n表示木块标号
while (cin >> s1 ,s1!="quit")//这种写法和while(cin>>s1&&s1!="quit")一致
{
cin>> a >> s2 >> b;//输入move a onto b;
int pa, pb, ha, hb;
find_block(a, pa, ha);//返回后 pa表示a木块在哪一堆,ha表示a木块的高度;
find_block(b, pb, hb);//同上分表表示b木块的信息
if (pa == pb) continue;//非法指令 这个表现思维的严谨性
if (s2 == "onto") clear_above(pb, hb);
if (s1 == "move") clear_above(pa, ha);
pile_onto(pa, ha, pb);
}
print();//打印输出
return 0;
}
读到这里我还要写一下书上我认为比较重要的内容:找出每个指令的共同点,编写函数以减少重复代码 。一个大题要分解若干个小题,找到每个小题间的共性可以在一定程度减少思维负担,也为之后找BUG提供有利帮助。
6.1 empty()函数的使用
废话少说,看代码就懂了:
#include<iostream>
#include<cstdio>
#include<string>
using namespace std;
int main()
{
string s,s1;
s="sdadsadadasa";
s1="";
if(s.empty())
cout<<"s为空"<<endl;
if(s1.empty())
cout<<"s1为空"<<endl;
return 0;
}
这一小结就先写到这里,内容有些不足,我会在后续进行补充,修饰。
2020//11//2 22:06