目录:
本周学习内容:
1.STL的应用。
2.搜索方面的一些知识。
3.图论最短路径生成。
一,STL
基础内容:
进阶知识:
1.vector
应用场景:
a.适用于随机访问,访问量比较大(因为随机访问的时间复杂度只有O(1)),相对而言插入和删除操作较小。
b.结合本周所学习的图论,可以用vector建立邻接表,代码如下:
struct node {
int s1;//记录结点
int side;//边权
}
vector<node>mp[maxn];//本身就可以存储结构体
//也可以用vector<pair<int,int>>s
init();//初始化mp
node h;
//循环输入
int x,y,r;
h.s1 = y;
h.side = r;
mp[x].push_back(h);//从x到y,路径为r
注意的是vector可以设为二维数组进行操作。 (pair的用法之前有讲)。
c.经典->约瑟夫问题:
P1996 约瑟夫问题
题目描述
n 个人围成一圈,从第一个人开始报数,数到 m 的人出列,再由下一个人重新从 1 开始报数,数到 m 的人再出圈,依次类推,直到所有的人都出圈,请输出依次出圈人的编号。
注意:本题和《深入浅出-基础篇》上例题的表述稍有不同。书上表述是给出淘汰 n-1 名小朋友,而该题是全部出圈。
输入格式:
输入两个整数 n,m。
输出格式:
输出一行 n个整数,按顺序输出每个出圈人的编号。
输入输出样例:
输入:
10 3
输出:
3 6 9 2 7 1 8 5 10 4
说明/提示:
1≤m,n≤100
题目分析:
1.本题形成了一个圆桌问题。(寻找到的点对数组现有元素个数进行取余)
2.找到的点删除,直到数组为空。
#include <iostream>
#include <vector>
using namespace std;
vector<int>s;
//感觉知识掌握的还是不够牢固
int main()
{
int n, m;
int pos = 0;
cin >> n >> m;
for (int i = 1; i <= n; i++) {
s.push_back(i);
}
while (!s.empty()) {
pos = (pos + m-1) % s.size();
cout << s[pos] << " ";
s.erase(s.begin()+pos);
}
}
2.stack
应用场景:
1.需要逆序输出时。(因为栈的最大特点就是先进后出)
2.计算后缀表达式。(例如:括号匹配,符号成对出现等)
3.数制转换也可以用栈来实现。
栈的例题:
例题1:(解释一下,我本来想直接粘贴题目的,奈何推荐受限)
P1449 后缀表达式
题目描述:
所谓后缀表达式是指这样的一个表达式:式中不再引用括号,运算符号放在两个运算对象之后,所有计算按运算符号出现的顺序,严格地由左而右新进行(不用考虑运算符的优先级)。
如:3*(5–2)+7对应的后缀表达式为:3.5.2.-*7.+@。’@’为表达式的结束符号。‘.’为操作数的结束符号。
输入格式:
输入:后缀表达式
输出格式:
输出:表达式的值
输入输出样例:
输入:
3.5.2.-*7.+@
输出 :
16
说明/提示:
字符串长度,1000内。
题目分析:
1.首先必须了解后缀表达式是如何计算的(
一看就会的知识)2.字符串转化数字,当遍历到“.”时,压入栈内。
3.遇到数乘符号时弹出两个栈顶元素,计算之后再次压入栈内,循环,直到遇到“@”结束循环,栈内剩余值,即为后缀表达式所求值。
代码如下:
#include <iostream>
#include <stack>
#include <cstdio>
using namespace std;
int s=0;
char ch;
stack<int>n;
int main()
{
int x;
int y;
do {
ch = getchar();
if (ch >= '0' && ch <= '9') {
s = s * 10 + ch - '0';
}
else if (ch == '.') {
n.push(s);
s = 0;
}
else if (ch != '@') {
x = n.top(); n.pop();
y= n.top(); n.pop();
switch (ch)
{
case '+':n.push(x + y); break;
case '-':n.push(y-x); break;//是栈顶的第二个元素-第一个元素
case '*':n.push(x *y); break;
case '/':n.push(y/x); break;
}
}
} while (ch != '@');
cout << n.top()<<endl;//取剩余的栈顶元素
}
例题2:
十进制转二进制,(因为栈这个本质是一个先进后出的结构)。
#include <iostream>
#include <vector>
#include <stack>
using namespace std;
vector<int>s;
//感觉知识掌握的还是不够牢固
int main()
{
stack<int>s;
int n;
cin >> n;
while (n>0) {
s.push(n % 2);
n = n / 2;
}
int size = s.size();
for (int i =0; i <size; i++) {
cout << s.top();
s.pop();
}
}
3.queue
应用场景:
1.队列这个应用场景相对而言会更加广泛一点,首先它是一个先进先出的结构类型。
2.结合这个星期所学的,主要应用在BFS(广度优先搜索)。
3.图的最短路径(SFPA算法中有应用)
详情队列使用请看:
总体来说,这是我最熟悉的STL里的函数,队列的使用范围是比较广泛的,但是仍然要注意队列的一些基础操作。特别是关于搜索问题的回溯方面,一定要特别注意。
4.priority_queue 优先队列
概念解析:
无非就是优先级高的先进行出队操作。就是个大顶堆的操作,最大的元素在堆顶(回想堆排序我到现在还没写,今晚赶出来)
例题:
(这里例题来源于费费的课件,因为我觉得这个题目就很适合我理解优先队列的使用,我很菜)
判断下列的点哪个离原点最远,并输出那个点的x,y值。
输入:(输入n,接下来输入n个点)
3
3 2
1 2
2 2
输出:(输出最大距离那个点的x,y坐标)
3 2
利用优先队列,运算符重载,代码如下:
#include<iostream>
#include <queue>
#define pow2(a)((a)*(a))//宏定义
#define dist2(x,y)(pow2(x)+pow2(y))
using namespace std;
struct node {
int x;
int y;
friend bool operator<(node a,node b) {//运算符重载,重载这个"<"
return (dist2(a.x, a.y) < dist2(b.x, b.y));
/*const bool operator<(const node&b){//运算符重载,重载这个"<"
return (dist2(x,y)<dist2(b.x,b.y));
}(这个报错了)*/
}
};
int main()
{
priority_queue<node>s;
int n;
int x, y;
cin >> n;
while (n--) {
node p;// p定义一个结构体类型的变量,接收x,y;
cin >> x >> y;
p.x = x; p.y = y;
s.push(p);
}
cout << s.top().x << " " << s.top().y << endl;
}
6.sort
sort,可谓是我接触的最多的函数了。
应用场景:
1.给无序数组进行排序。(可以是任何类型,进行降序,升序)
2.用于结构体排序(应用十分广泛,主要是将bool cmp函数给写好,自定义排序准则)
例题:(关于结构体排序的一道题目)
P1068 [NOIP2009 普及组] 分数线划定
输入 :
6 3
1000 90
3239 88
2390 95
7231 84
1005 95
1001 88
输出:
88 5
1005 95
2390 95
1000 90
1001 88
3239 88
题目分析:(
说实话,我都不想分析,对我来说这个不太难懂)
1.思考问题:bool 函数该如何写?先按成绩从降序排列,如果成绩相同按学号升序排列。
2.思考问题2:如何去统计和m*1.5分数相同的人,用循环找到最后一个和这个分数相同的人的下标。从上到下输出即可。
代码如下:
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
struct student {
int nums;
int score;
}a[6000];
bool cmp(student x, student y) {//判断准则
if (x.score == y.score) {
return x.nums < y.nums;
}
return x.score > y.score;
}
int main()
{
int n, m;
int p = 0;
int k = 0;
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> a[i].nums >> a[i].score;
}
sort(a + 1, a + n + 1, cmp);
p =floor(m*1.5);
for (int i = p; i <= n; i++) {
if (a[p].score == a[i].score) {
k = i;//记录下标
}
}
cout << a[p].score << " " << k << endl;
for (int i = 1; i <= k-1; i++) {
cout << a[i].nums << " " << a[i].score << endl;
}
cout << a[k].nums << " " << a[k].score;
}
7.unique(去重函数)
应用场景:
就是去除相邻元素的重复值,只保留一个相同的元素。
所以,注意的是使用之前先用sort进行排序。(其实重复的值并没有被删除,而是排到了数组后面去了)。
代码实现一下(特别水):
#include<iostream>
#include <algorithm>
using namespace std;
int main()
{
int n;
int a[100];
cin >> n;
for (int i = 0; i < n; i++) {
cin >> a[i];
}
sort(a, a + n);
int h = unique(a, a + n) - a;//用一个新的数接收去重之后数组的长度
for (int i = 0; i < h; i++) {
cout << a[i] << " ";
}
}
8.next_permutation(全排列)
分析:
按字典序进行全排列。
我们学校的例题:
水一道代码:
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
int main()
{
int n;
cin >> n;
int a[15];
for (int i = 1; i <= n; i++) {
a[i] = i;
}
do {
for (int i = 1; i <= n; i++) {
cout << a[i] << " ";
}
cout << endl;
} while (next_permutation(a + 1, a + n + 1));
}
9.upper_bound、lower_bound
解析:
upper_bound:返回>所给数值元素的第一个位置。
lower_bound:返回>=所给数值元素的第一个位置。
10.set/multiset(集合)
基础知识里面基本操作总结的已经很全面了,因为本人只做过一道关于set集合的题目,具体应用场景还待我继续研究(其实我是真的不知道这个用在哪)
11.map/multimap
分析:
映射的原理,用键值返回元素。
应用例题:
P5266 【深基17.例6】学籍管理
题目描述:
输入输出样例
输入 :
5
1 lxl 10
2 lxl
3 lxl
2 lxl
4
输出:
OK
10
Deleted successfully
Not found
0
题目分析:
1.深入浅出上的例题,个人觉得比较经典,4个操作,储存(用姓名作为键值,储存映射成绩)。
2. 查询和删除,注意find函数,如果查询不到就返回最后一个迭代器的位置,可以用于检查这个人是都存在。
3.剩下的就是计算当前map元素个数,size即可,分支结构而已,算是比较基础的了。
#include <iostream>
#include <map>
using namespace std;
map<string, int>s;
int n,m;
string name;
int score;
int main()
{
cin >> n;
while (n--) {
cin >> m;
if (m == 1) {
cin >> name >> score;
s[name] = score;
cout << "OK" << endl;
}
else if (m == 2) {
cin >> name;
if (s.find(name) != s.end()) {
cout << s[name] << endl;
}
else {
cout << "Not found" << endl;
}
}
else if (m == 3) {
cin >> name;
if (s.find(name) != s.end()) {
s.erase(s.find(name));
cout << "Deleted successfully" << endl;
}
else {
cout << "Not found" << endl;
}
}
else {
cout << s.size() << endl;
}
}
}
二,图的最短路径算法
直接看我关于图的总结吧->
三,最终总结:
1.个人觉得还是在细节上的把握很差。(特别是STL在算法中应用很广泛)
2.周六周日的任务就是将这周所学习的知识复习,不能只贪图速度而忽视效率。
3.算法这个东西就是要多思考,不能盲目的刷题,这周的东西还是不少,灵活运用才是关键。
4.也是刚开始写这个博客,所以有什么不好的地方还是需要及时指正。
5.希望能通过本周的学习,复习,总结,形成更强的知识网络体系,最终实践在题目中去。
那这周的总结就到这里结束了,细节的补充还会继续更新,生死看淡,不服就干!