算法蓝桥杯算法蓝桥杯算法
GuoTianyu目录
*
表示该算法在蓝桥杯中的重要程度,最高5颗星,最低1颗星。
基础算法(这些不会就放弃蓝桥杯吧)
- 最大公约数(gcd)和最小公倍数(lcm)(
*****
)
- 日期是否合法(包含闰年和平年判断)(
*****
)
- 数的拆分 (
*****
)
- 判断质数(
***
)
- 组合排列(
***
)
- 排序 (
**
)
蓝桥杯必备算法(***
以上必须掌握)
- 模拟 (
*****
)
- DFS(深度优先搜索) (
*****
)
- BFS(广度优先搜索)(
****
)
- 二分查找(
****
)
- 哈希数组(
****
)
- 前缀和(
****
)
- 简单DP(
***
)
- 贪心(
***
)
- 优先队列 (
***
)
- 双指针 (
***
)
- 差分(
**
)
- 树状数组 (
*
)
常用方法以及库函数
- 输入
- 输出
- 自动类型转换auto
算法实例
基础算法
1. 最大公约数(gcd)和最小公倍数(lcm)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| #include<iostream> using namespace std;
int gcd(int a, int b) { return b ? gcd(b, a % b) : a; }
int lcm(int a,int b) { return a*b/gcd(a,b); }
int main() { int n,m; cin>>n>>m; cout<<"n和m的最大公因数是:"<<gcd(n,m)<<endl; cout<<"n和m的最小公倍数是:"<<lcm(n,m)<<endl; }
|
2.日期是否合法(包含闰年和平年判断)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| #include<iostream> using namespace std;
int month[]={0,31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
bool isRunYear(int year) { return (year%4==0&&year%100!=0 || year%400==0); } int main() { int year; cin>>year; if(isRunYear(year)) { month[2]++; } for(int i=1;i<=12;i++) { cout<<month[i]<<endl; } }
|
3.数的拆分
- 给定一个整数n(范围1~1e9),求各位数上的和。例n=123,则sum=1+2+3=6
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| #include<iostream> using namespace std;
int getSum(int n) { int sum=0; while(n) { sum+=n%10; n/=10; } return sum; } int main() { int n; cin>>n; cout<<getSum(n); }
|
- 给定一个整数n(范围1~1e9)和某个位数m,输出该正整数n上的m位的值。如n=123,m=3,则num=1,n百位数上的值是1。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| #include<iostream> #include<cmath> using namespace std;
int getNum(int n,int m) { return (n/(int)pow(10,m-1))%10; } int main() { int n,m; cin>>n>>m; cout<<getNum(n,m); }
|
4.判断质数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| #include<iostream> #include<cmath> using namespace std;
bool isPrime(int n) { if(n<=1)return false; for(int i=2;i<=sqrt(n);i++) { if(n%i==0)return false; } return true; } int main() { int n; cin>>n; if(isPrime(n))cout<<n<<"是质数"; else cout<<n<<"不是质数"; }
|
5.组合排列
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| #include<iostream> #include<cmath> using namespace std;
long long factorial(int n) { if (n == 0 || n == 1) return 1; long long result = 1; for (int i = 2; i <= n; ++i) { result *= i; } return result; }
long long permutation(int n, int k) { if (k > n) return 0; return factorial(n) / factorial(n - k); }
long long combination(int n, int k) { if (k > n) return 0; return factorial(n) / (factorial(k) * factorial(n - k)); }
int main() { int n,k; cin>>n>>k; cout<<permutation(n,k)<<endl; cout<<combination(n,k)<<endl; }
|
6.排序
1 2 3
| void sort(RandomIt first, RandomIt last, Compare comp); void sort(RandomIt first, RandomIt last);
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| #include<iostream> #include<algorithm> using namespace std;
bool temp(int n1,int n2) { return n1>n2; } int main() { int arr[]={1,5,9,8,4,6,7,10}; int size=sizeof(arr)/sizeof(arr[0]); sort(arr,arr+size); for(int i=0;i<size;i++) { cout<<arr[i]<<" "; } cout<<endl; sort(arr,arr+size,temp); for(int i=0;i<size;i++) { cout<<arr[i]<<" "; } }
|
- 特殊情况下需要使用某种排序,比如逆序对就要使用归并排序,这里冒泡和归并用得多。
- 归并排序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| #include<cstring> #include<iostream> #include<algorithm> using namespace std;
const int N = 100010; int n; int q[N],w[N]; void merge_sort(int l,int r) { if(l>=r)return; int mid = l + r >> 1; merge_sort(l,mid); merge_sort(mid+1,r); int i=l,j=mid+1,k=0; while(i<=mid&&j<=r) { if(q[i]<q[j]) { w[k++]=q[i++]; }else { w[k++]=q[j++]; } } while(i<=mid) { w[k++]=q[i++]; } while(j<=r) { w[k++]=q[j++]; } for(i = l,j=0;i<=r;i++,j++)q[i]=w[j];
} int main() { cin>>n; for(int i=0;i<n;i++) { scanf("%d",&q[i]); } merge_sort(0,n-1); for(int i=0;i<n;i++) { printf("%d ",q[i]); } return 0; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| #include<iostream> #include<algorithm> using namespace std; int n,arr[100]; void bubble_Sort(int arr[],int n) { for(int i=0;i<n-1;i++) { for(int j=0;j<n-1-i;j++) { if(arr[j]>arr[j+1]) { int t=arr[j]; arr[j]=arr[j+1]; arr[j+1]=t; } } } } int main() { cin>>n; for(int i=0;i<n;i++) { scanf("%d",&arr[i]); } bubble_Sort(arr,n); for(int i=0;i<n;i++) { printf("%d ",arr[i]); } }
|
蓝桥杯必备算法
1.模拟
没有具体的模板,模拟就是根据题意来还原场景,从而做出解答,多练即可。
2.DFS(深度优先搜索)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| #include<iostream> using namespace std; void dfs(递归参数) { if(递归参数太离谱了) { return; } if(终止条件) { return; } for(枚举每种方案) { 状态记录 dfs(下一个递归参数); 状态还原 } } int main() { dfs(递归参数); }
|
3.BFS(广度优先搜索)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
|
一个迷宫由 R行 C列格子组成,有的格子里有障碍物,不能走;有的格子是空地,可以走。 给定一个迷宫,求从左上角走到右下角最少需要走多少步(数据保证一定能走到)。 只能在水平方向或垂直方向走,不能斜着走。
5 5 ..### #.... #.#.# #.#.# #.#..
#include<iostream> #include<cstring> #include<queue> #define x first #define y second int dx[]={0,0,1,-1}; int dy[]={1,-1,0,0}; using namespace std; typedef pair<int,int> PII; const int N=45; int r,c; char g[N][N]; int a[N][N]; void bfs(int sx,int sy) { queue<PII> q; memset(a,-1,sizeof a); a[sx][sy]=1; q.push({sx,sy}); while(!q.empty()) { auto t =q.front(); q.pop(); for(int i=0;i<4;i++) { int xx = dx[i]+t.x; int yy = dy[i]+t.y; if(xx<0||xx>r-1||yy<0||yy>c-1)continue; if(a[xx][yy]!=-1)continue; if(g[xx][yy]!='.')continue; q.push({xx,yy}); a[xx][yy]=a[t.x][t.y]+1; } if(t.x==r-1&&t.y==c-1) { cout<<a[t.x][t.y]; } } } int main() { cin>>r>>c; for(int i=0;i<r;i++) { for(int j=0;j<c;j++) { cin>>g[i][j]; } } bfs(0,0); }
|
4.二分查找
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| #include<iostream> using namespace std;
bool check(int num) { } int main() { int l=左边界-1; int r=右边界-1; while(l+1<r) { int mid = l+r>>1; if(check(mid)) { } else { } } if(check(l)&&check(r)) { } else if(check(l)) { } else if(check(r)) { } }
|
5.哈希数组
前置知识:输出某个字符的ASCII值。(所以ACSII值不需要记,考场直接输出即可)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| #include<iostream> using namespace std;
int main() { cout<<"A字符的ASCII"<<int('A')<<"\n"; cout<<"1字符的ASCII"<<int('1')<<"\n"; cout<<"?字符的ASCII"<<int('?')<<"\n"; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
|
#include<iostream> #include<cstring> using namespace std;
int hash[130]={0}; int main() {
string s="123456ABCZZZaaaccc"; for(int i=0;i<s.size();i++) { hash[s[i]]++; } for(int i=0;i<130;i++) { if(hash[i]!=0) { cout<<char(i)<<"出现了"<<hash[i]<<"次"<<endl; } } }
|
6.前缀和
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
#include<iostream> #include<cstring> using namespace std; const int N =100; int n,l,r; int arr[N]; long long int sum[N]; int main() { cin>>n>>l>>r; for(int i=1;i<=n;i++) { cin>>arr[i]; } for(int i=1;i<=n;i++) { sum[i]=sum[i-1]+arr[i]; } cout<<sum[r]-sum[l-1]; }
|
7.简单DP
- 通过当前状态和上个状态之间的某种关系,得出最优解。
- 多做题,能够找到状态转移方程即可。
- 无固定模板。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
#include<iostream> #include<cstring> using namespace std; int f[N][N]; int main() { for(枚举第一个值i) for(枚举第二个值j) f[i][j] = (f[i][j]或者f[i-1][j]或者f[i][j-1].....进行状态转移) cout<<f[N-1][N-1]; cout<<f[0][0]; }
|
8.贪心
- 局部最优解就是全局最优解,每一步都要保证是最优的,因此需要证明。
- DP可以替代弹性
- 没有模板,多做题
9.优先队列
- 一种堆的数据结构
- 有序队列,并且插入和修改不改变原有的有序性
- 不需要记,考试可以查看C++帮助手册
- 注意包含头文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| #include<iostream> #include<queue> #include<vector> using namespace std;
int main() { priority_queue<int,vector<int>,greater<int> > q; q.push(3); q.push(13); q.push(4); q.push(0); q.push(8); while(!q.empty()) { cout<<q.top()<<endl; q.pop(); } }
|
10.双指针
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| #include<iostream> using namespace std;
int main() {
for(int i=0,j=0;i<n;i++) { while(j<i) { j++; } } }
|
11.差分
- 区间修改,在某个区间里面的所有元素增加或者减少某个值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
|
#include<iostream>
using namespace std; const int N = 100; int arr[N]; int n,k; int d[N]; int res[N]; int main() { cin>>n>>k; for(int i=0;i<n;i++)cin>>arr[i]; while(k--) { int l,r; cin>>l>>r; d[l]++; d[r+1]--; } for(int i=1;i<n;i++) { d[i]=d[i]+d[i-1]; }
for(int i=0;i<n;i++) { res[i]=arr[i]+d[i]; } for(int i=0;i<n;i++) { cout<<res[i]<<" "; } }
|
12.树状数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
|
#include<iostream> using namespace std; int n,m; const int N=100005; int a[N],tr[N]; int lowbit(int x) { return x & -x; } void add(int x,int v) { for(int i=x;i<=n;i+=lowbit(i)) { tr[i]+=v; } } int query(int x) { int res=0; for(int i=x;i;i-=lowbit(i)) { res+=tr[i]; } return res; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); } for(int i=1;i<=n;i++) { add(i,a[i]); } int k,x,y; while(m--) { scanf("%d%d%d",&k,&x,&y); if(k==0) { printf("%d\n",query(y)-query(x-1)); }else { add(x,y); } } }
|
常用方法以及库函数
1.输入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
#include<iostream> #include<string>
using namespace std; int main() { string s; getline(cin,s); cout<<s; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
#include<iostream> #include<string>
char ch[15]; using namespace std; int main() { scanf("%s",&ch); cin>>ch; cout<<ch[2]; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
#include<iostream>
int year,month,day; using namespace std; int main() { scanf("%d-%d-%d",&year,&month,&day);
cout<<year<<"年"<<month<<"月"<<day<<"日"; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
#include<iostream>
int n=0; int arr[100]; using namespace std; int main() { while(cin>>arr[n++]); n--; cout<<"共有"<<n<<"个数据"; }
|
2.输出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
#include<iostream>
using namespace std; int main() { for(int i=1;i<=10;i++) { printf("%02d ",i); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
#include<iostream>
using namespace std; int main() { for(float i=1;i<=5;i++) { printf("%.2f ",i/3); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| #include<iostream>
using namespace std; int main() {
int a=104; int b=96; cout<<((a+5)/10)*10<<endl; cout<<((b+5)/10)*10<<endl;
float c=0.564; float d=0.595;
printf("%.2f\n",c); printf("%.2f\n",d);
float e = 9.99; float f = 5.49; printf("%d\n",(int)(e+0.5)); printf("%d\n",(int)(f+0.5)); }
|
3.自动类型转换auto
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| #include<iostream> #include<vector>
using namespace std; int main() { vector<int> v; for(int i=0;i<10;i++) v.push_back(i); for(auto it=v.begin();it!=v.end();it++) { cout<<*it<<" "; } }
|