天天看点

算法竞赛入门经典 c++与STL入门 1

算法竞赛入门经典 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

继续阅读