算法竞赛从入门到进阶

算法竞赛从入门到进阶

1.算法竞赛概述

1.1 C语言中输入输出函数

  • putchar()
  • getchar
  • printf()
  • scanf()
  • puts()
  • gets()
  • sscanf()

1.2 输入结束方式

while(scanf("%d %d",&a,&b) != EOF){
    
}
//等价于
while(~scanf("%d %d",&a,&b)){
    //一般使用这种方式
}

1.3 编码技巧

把长字符重新定义成段字符 节省编码时间

typedef long long ll;
long long a;
//变为
ll a;

1.4 最好不要用宏定义 容易出现问题

使用const定义常量 例如

const int MAX=100005;

把宏函数写成普通函数

2.STL和基本数据结构

2.1 容器

顺序式容器 vector list deque queue priority_queue stack等

关联式容器 set multiset map multimap等

2.1.1 vector

动态数组

定义

vector<int> a;

vector<int> a(100);

vector<int> a(100,5);

vector<string> b(a.begin(),a.end());

操作

a.push_back(100);
int size=a.size();
bool isEmpty=a.empty();
count<<a[0]<<endl;
a.insert(a.begin()+i,k); //在第i个元素前面插入k
a.insert(a.end(),10,5); //在尾部插入10个值为5的元素
a.pop_back();
a.erase(a.begin()+i,a.begin()+j);//删除区间[i,j-1]的元素
a.erase(a.begin()+2); //删除第三个元素
a.resize(n);
a.clear();
reverse(a.begin(),a.end());
sort(a.begin(),a.end());
2.1.2 stack

操作

stack<type> s;
s.push(item);
s.top(); //返回栈顶元素 但不会删除
s.pop(); //删除栈顶元素 但不会返回
//一般是先返回在删除 所以先top 在pop
s.size();
s.empty();
2.1.3 queue

操作

queue<type> q;
q.push(item);
q.pop();
q.front(); //返回队首元素但不会删除
q.back();
q.size();
q.empty();
2.1.4 priority_queue

优先队列

在STL中,优先队列是用二叉堆来实现的,优先级最高的先出队。每次的push和pop操作,优先队列都会动态的调整,把优先级最高的元素放在前面。

操作

q.top();//返回优先级最高的元素值 但不删除
q.pop();
q.push(item);
2.1.5 链表 list

STL中的list是双向链表

函数原型:

  • list<T> lst; //list采用采用模板类实现,对象的默认构造形式:
  • list(beg,end); //构造函数将[beg, end)区间中的元素拷贝给本身。
  • list(n,elem); //构造函数将n个elem拷贝给本身。
  • list(const list &lst); //拷贝构造函数。

功能描述:

  • 给list容器进行赋值,以及交换list容器

函数原型:

  • assign(beg, end); //将[beg, end)区间中的数据拷贝赋值给本身。
  • assign(n, elem); //将n个elem拷贝赋值给本身。
  • list& operator=(const list &lst); //重载等号操作符
  • swap(lst); //将lst与本身的元素互换。

功能描述:

  • 对list容器的大小进行操作

函数原型:

  • size(); //返回容器中元素的个数

  • empty(); //判断容器是否为空

  • resize(num); //重新指定容器的长度为num,若容器变长,则以默认值填充新位置。

    ​ //如果容器变短,则末尾超出容器长度的元素被删除。

  • resize(num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置。

      	 	 	​					    //如果容器变短,则末尾超出容器长度的元素被删除。
    

功能描述:

  • 对list容器进行数据的插入和删除

函数原型:

  • push_back(elem);//在容器尾部加入一个元素
  • pop_back();//删除容器中最后一个元素
  • push_front(elem);//在容器开头插入一个元素
  • pop_front();//从容器开头移除第一个元素
  • insert(pos,elem);//在pos位置插elem元素的拷贝,返回新数据的位置。
  • insert(pos,n,elem);//在pos位置插入n个elem数据,无返回值。
  • insert(pos,beg,end);//在pos位置插入[beg,end)区间的数据,无返回值。
  • clear();//移除容器的所有数据
  • erase(beg,end);//删除[beg,end)区间的数据,返回下一个数据的位置。
  • erase(pos);//删除pos位置的数据,返回下一个数据的位置。
  • remove(elem);//删除容器中所有与elem值匹配的元素。
2.1.6 set

set 就是集合 STL中的set用二叉搜索树实现,集合中的每个元素只出现一次并排好序的。访问元素的时间复杂度是O(nlogn);

操作

set<type> A;
A.insert(item);//插入元素
A.erase(item);//删除元素
A.clear();
A.empty();
A.size();
A.find(k); //返回一个迭代器,指向键值k
A.lower_bound(k);//返回一个迭代器,指向键值不小于k的第一个元素
A.upper_bound();//返回一个迭代器,指向键值大于k的第一个元素
2.1.7 map

简介:

  • map中所有元素都是pair
  • pair中第一个元素为key(键值),起到索引作用,第二个元素为value(实值)
  • 所有元素都会根据元素的键值自动排序

本质:

  • map/multimap属于关联式容器,底层结构是用二叉树实现。

优点:

  • 可以根据key值快速找到value值

功能描述:

  • map容器进行插入数据和删除数据

函数原型:

  • insert(elem); //在容器中插入元素。
  • clear(); //清除所有元素
  • erase(pos); //删除pos迭代器所指的元素,返回下一个元素的迭代器。
  • erase(beg, end); //删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器。
  • erase(key); //删除容器中值为key的元素。

功能描述:

  • 对map容器进行查找数据以及统计数据

函数原型:

  • find(key); //查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end();
  • count(key); //统计key的元素个数

学习目标:

  • map容器默认排序规则为 按照key值进行 从小到大排序,掌握如何改变排序规则

主要技术点:

  • 利用仿函数,可以改变排序规则

示例:

#include <map>

class MyCompare {
public:
	bool operator()(int v1, int v2) {
		return v1 > v2;
	}
};

void test01() 
{
	//默认从小到大排序
	//利用仿函数实现从大到小排序
	map<int, int, MyCompare> m;

	m.insert(make_pair(1, 10));
	m.insert(make_pair(2, 20));
	m.insert(make_pair(3, 30));
	m.insert(make_pair(4, 40));
	m.insert(make_pair(5, 50));

	for (map<int, int, MyCompare>::iterator it = m.begin(); it != m.end(); it++) {
		cout << "key:" << it->first << " value:" << it->second << endl;
	}
}
int main() {

	test01();

	system("pause");

	return 0;
}

总结:

  • 利用仿函数可以指定map容器的排序规则
  • 对于自定义数据类型,map必须要指定排序规则,同set容器

2.2 sort()

void sort(RandomAccessItarator first,RandomAccessItarator last); 包括first 但不包括last

void sort(RandomAccessItarator first,RandomAccessItarator last,Compare mycompare); 包括first 但不包括last 自己定义的比较规则

比较规则:less()升序 greater()降序

2.2 next_permutation()

STL提供求下一个排列组合的函数next_permutation() 例如a,b,c三个字符组成的序列,next_permutation()函数能按照字典序返回6个组合 即abc acb......

bool next_permutation(BidrectionalIterator first,BidrectionalIterator last); 包括first 不包括last

bool next_permutation(BidrectionalIterator first,BidrectionalIterator last,Compare mycompare);

有下一种排列组合的话返回true 否则false。

每调用一次,就会把新的排列放到原来的空间里。

复杂度O(n)

一般使用该函数的适合,初始序列一般是一个字典序的最小序列,如果不是,可以调用sort()函数进行排序得到最小序列,再使用该函数。

#include <iostream>
#include<algorithm>
using namespace std;
int a[1001];
int m;
int main()
{
   cin.sync_with_stdio(false);
   cin.tie(nullptr);
   cin>>m;
   for (int i = 1; i <= m; i++)  a[i]=i;
   do{
        for (int i = 1; i <= m; i++) cout<<a[i]<<" ";
        cout<<endl;
   }while(next_permutation(a+1,a+m+1));
   return 0;
}

测试结果

3                                 
1 2 3 
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1

3.搜索技术

搜索使用的算法是BFS和DFS,DFS用递归来实现,BFS用队列来实现。

搜索算法的思想就是暴力法,可以在暴力的过程中进行优化,利用剪枝函数减少搜索空间,提高效率。

3.1 递归和排列

x=x&(x-1) 功能是消除x的二进制数的最后一位1,利用这个操作可以计算出二进制中1的个数。

用num统计1的个数,每次执行x=x&(x-1) 操作后 num++,直到x=0。

posted @ 2021-08-29 16:20  guoyuxin3  阅读(306)  评论(0)    收藏  举报