赞
踩
转眼间,蓝桥杯真的近在咫尺了,正赛即将开始!
小博主作为本次参加蓝桥杯算法大赛的一员,心情也是非常忐忑!
但忐忑归忐忑,还是要静下心来,再梳理一波算法和可能的考点!
希望对大家能有帮助,衷心祝愿友友们都能取得理想的成绩!
好的数据结构,不仅让题目思路非常明朗,还能增加通过的概率,最重要的有时可以解决掉可恶的运行超时!
vector数组优点在于无限大,一般不会出现内存溢出的情况,一维二维都很适合。还可以搭配结构体,非常好用。
vector<Type> a; //一维
vector<Type> b[100]; //声明一个100行,不限列的二维数组,其实超过100行完全可以
#include<bits/stdc++.h>
using namespace std;
vector<int>q[10];
int main()
{
q[13].push_back(1);
cout<<q[13][0]<<endl;
return 0;
}
注意是push_back( )
sort(q.begin(),q.end()) //默认升序排序
bool cmp(int a,int b)
{
return a>b;
}
sort(q.begin(),q.end(),cmp) //降序排序
q.erase(q.begin()+pos); //删除单个,pos对应的位置为要删除的元素
q.erase(q.begin()+start,q.begin()+end); //删除start到end之间的元素
删除这个功能其实挺好的,普通数组删完中间如果需要整体前移,显然用vector更好
栈的特点在于先进先出,比如计算表达式的值,可以用栈存储数字和符号,是个不错的选择
stack<Type> q;
q.push(); //入栈操作
q.top(); //读取栈顶元素
q.pop(); //删除栈顶元素
q.size(); //返回栈中元素个数
q.empty(); //检查栈是否为空
队里的特点是先进先出,是BFS算法的核心数据结构
queue<Type> q;
q.push(); //入栈操作
q.front(); //读取队列第一个元素
q.pop(); //删除队首元素
q.back(); //返回队尾元素
q.size(); //返回栈中元素个数
q.empty(); //检查栈是否为空
默认由大到小排序,可以手动改为由小到大
#include<bits/stdc++.h>
using namespace std;
priority_queue<int, vector<int>, greater<int>> q; //改为从小到大排序
bool cmp(int a,int b)
{
return a>b;
}
int main()
{
q.push(0);
q.push(1);
cout<<q.top()<<endl;
return 0;
}
比如用于求最短路径的迪杰斯塔拉算法
set和优先队列类似,也是一个有序的集合,然后区别就在于set能够去重,即不会存在重复的元素。
声明方式:
set<Type> q;
常用操作:
set.insert(); //插入数据
set.erase(); //删除数据
set.empty(); //判断是否为空
set.size(); //返回元素个数
set.find(k); //返回一个迭代器,指向键值k
map容器能够实现关联,即把A和B通过key->value的方式关联到一起。
声明方式:
map<type1,type2>m;
常用操作:
m[key]=value; //直接赋值
for(map<type1,type2>::iterator it=m.begin();it!=m.end();it++) //生成迭代器
{
cout<<"key"<<it->first<<endl;
cout<<"value"<<it->value<<endl;
}
这一部分相当灵活了,需要根据自己和题目的需求灵活确定结构体
struct point
{
int x;
int y;
point(int a,int b)
{
x=a;
y=b;
}
point(){}
bool opeartor <(const point&a)const //这一步是用来重载运算符的操作,目的是为了让优先级队列
{ //从小到大输出,这个背一下模版就可以,一般用的概率不大
retuan x>a.x;
}
}
俗话说,好的工具是成功的一半,现在我们已经有了强大的 stl 库和编写好的结构体,是时候真正进入算法部分了
int gcd(int a,int b)
{
if(a<b)
{
int temp=a;
a=b;
b=temp;
}
if(b==0)
return a;
else
return gcd(b,a%b);
}
最小公倍数=x*y / gcd(x,y)
遇到这类问题,直接上算法模版就完事了!
要快速的求出 a的n次方 是多少,那么就要用到快速幂公式
int fastPow(int a, int n)
{
if(n==1)
return a;
int temp=fastPow(a,n/2);
if(n%2==1)
return temp*temp*a;
else
return temp*temp;
}
解释一下原理,快速幂就快在采用了类似二分法的思想,比如求一个2的16次方,正常的话用for循环累乘16个2,但是快速幂的方法就是看成先求 2²,然后再求2² * 2²,然后再求 (2² * 2²)*(2² * 2²),然后再求
((2² * 2²)(2² * 2²))((2² * 2²)*(2² * 2²)),总共进行了4次,就快速的达到了我们想要求的结果。
应用领域:最短路径问题,以及传播,感染之类的问题。笼统来讲就是由关于某个点可达性的问题。
主要知识点:
1 结构体struct point{} (这个看情况,不一定有)
2 方向数组dir[4][2] ={上,下,左,右}
3 dfs()算法,其实就是朝着某个方向一直走,走不通再回溯
此部分代码由我之前的一篇博客部分粘贴而来,感兴趣的可以看看原文 算法练习题38—蓝桥杯2018省赛“全球变暖”_杨大熊的代码世界的博客-CSDN博客
int dir[4][2]={{0,-1},{1,0},{0,1},{-1,0}}; //代表向左,向下,向右,向上,尽量和数组坐标保持一致 int flag=0; //不建议用数学中的坐标系,容易乱 struct point { int x; int y; }; bool check(int x,int y) { if(x>=1&&x<=n&&y>=1&&y<=n) { return true; } return false; } void dfs(point a) { juzhen[a.x][a.y]='*'; //证明被遍历 point temp=a; for(int i=0;i<4;i++) //分别为向左,向下,向右,向上 { temp.x=a.x+dir[i][0]; temp.y=a.y+dir[i][1]; if(check(temp.x,temp.y)&&juzhen[temp.x][temp.y]=='.') { dfs(temp); } else if(check(temp.x,temp.y)&&juzhen[temp.x][temp.y]=='#') { juzhen[temp.x][temp.y]='@'; } } return ; }
广搜和深搜解决的问题有很多类似,因此这两种方法都可以使用,但是小博主本身递归掌握的非常不好,因此更习惯用广搜。
主要知识点:
1 结构体struct point{} (这个看情况)
2 方向数组dir[4][2] ={上,下,左,右}
3 queue队列,核心中的核心
3 bfs()算法,将某个点的可达点全部装入queue中,弹出此点,然后再对queue中的下一个元素进行上述操作,直到队列为空。
int dir[4][2]={{-1,0},{0,-1},{1,0},{0,1}}; //依次为向左,向上,向右,向下 int Wx,Hy,num; #define CHECK(x,y)(x<Wx&&x>=0&&y>=0&&y<Hy) struct node { int x; int y; }; void BFS(int dx,int dy) { queue<node> q; //声明一个队列q,BFS算法的核心 num=1; node start,next; //开始节点和下一个节点 start.x=dx; start.y=dy; q.push(start); while(!q.empty()) { start=q.front(); q.pop(); for(int i=0;i<4;i++) { next.x=start.x+dir[i][0]; next.y=start.y+dir[i][1]; if(CHECK(next.x,next.y)&&room[next.x][next.y]=='.') { room[next.x][next.y]='#'; //进队之后标记被处理 num++; q.push(next); } } } }
动态规划,永远滴神!感觉动归真的是难度最高的一种。
个人感觉动归要写好,首先要把dp数组的结构想清楚,是建立一维的还是二维的,然后dp中每个状态的意义代表什么等等。
小蓝学习了最短路径之后特别高兴,他定义了一个特别的图,希望找到图 中的最短路径。
小蓝的图由 2021 个结点组成,依次编号 1 至 2021。
对于两个不同的结点 a, b,如果 a 和 b 的差的绝对值大于 21,则两个结点 之间没有边相连;如果 a 和 b 的差的绝对值小于等于 21,则两个点之间有一条 长度为 a 和 b 的最小公倍数的无向边相连。
例如:结点 1 和结点 23 之间没有边相连;结点 3 和结点 24 之间有一条无 向边,长度为 24;结点 15 和结点 25 之间有一条无向边,长度为 75。
请计算,结点 1 和结点 2021 之间的最短路径长度是多少。
答案:10266837
这个题建立一维的dp就非常合适,因为计算的是结点n到1的最短距离,不需要求n到x(随机指定)的距离,因此一维的就可以实现。
#include<bits/stdc++.h> using namespace std; int dp[2030]; //表示从i到1的距离 int gcd(int a,int b) { if(b==0) { return a; } else { return gcd(b,a%b); } } int main() { for(int i=1;i<=2021;i++) { for(int j=i+1;j<=i+21;j++) { if(dp[j]==0) { dp[j]=dp[i]+i*j/gcd(j,i); } else { dp[j]=min(dp[j],dp[i]+i*j/gcd(j,i)); } } } cout<<dp[2021]<<endl; return 0; }
你有一架天平和 N 个砝码,这 N 个砝码重量依次是 W1, W2,⋅⋅⋅, WN。
请你计算一共可以称出多少种不同的重量? 注意砝码可以放在天平两边。
输入格式
输入的第一行包含一个整数 N。
第二行包含 N 个整数:W1,W2,W3,⋅⋅⋅,WN。
输出格式
输出一个整数代表答案。
样例输入
3
1 4 6
1
2
样例输出
10
1
样例说明
能称出的 10 种重量是:1、2、3、4、5、6、7、9、10、11。
1=1;
2 = 6 − 4 (天平一边放 6,另一边放 4);
3=4−1;
4=4;
5=6−1;
6=6;
7=1+6;
9=4+6−1;
10=4+6;
11=1+4+6。
这个题建立就要建立二维的dp【i】【j】数组了,表示在当前已有的 i 种砝码下,是否可以称出重量 j 来
AC代码:
#include<bits/stdc++.h> using namespace std; int dp[105][100005]; int w[150]; int main() { int n; cin>>n; int sum=0; for(int i=0;i<n;i++) { cin>>w[i]; sum+=w[i]; } sort(w,w+n); //将砝码从小到大排列 dp[0][w[0]]=1; //第一个砝码先赋初值 for(int i=1;i<n;i++) //遍历砝码的次序 { dp[i][w[i]]=1; //当前重量一定可以称出,即只放这一个砝码 for(int j=1;j<=sum;j++) //对于每一种重量,分别判断 { if(dp[i-1][j]==1) //之前能凑出来这种重量 { dp[i][j]=1; dp[i][abs(j-w[i])]=1; dp[i][j+w[i]]=1; } } } int ans=0; for(int i=1;i<=sum;i++) { if(dp[n-1][i]==1) { ans++; } } cout<<ans<<endl; return 0; }
日期问题,贪心问题,还有一些字符串的操作,方法上可能没有模版,感觉更偏向平时的练习和考场发挥。
先写到这里吧,也非常感谢大家能够看完这些,写的比较仓促,没有太好的排版,见谅见谅。
最后再次祝各位友友们和我自己都能取得一个心目中理想的成绩!
天道酬勤!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。