整理:Littlefools(Zbt 小蒟蒻)
算法篇: 1. 搜索 DFS(深搜)void dfs(int depth){ //输入的是深度
if(depth==n){ //深度超出范围,说明找到一个解
//找到了一个解,对这个解进行处理包括但不限于解的数量,更新搜索最优值
return;
}
//扩展节点,比如
for(int i=1;i<=n;i++){ //处理节点
dfs(depth+1);
//部分问题需要恢复状态,如 N 皇后。
}
}
BFS(广搜)
queueq;//存储状态 void bfs(){ q.push(...)//初始状态入队 while(!q.empty()){ int s=q.front();q.pop();//获取状态 //处理结点 if(s 达到某种条件){ //输出或做些什么 return; } //扩展状态 for(int i=1;i<=n;i++){ int s; q.push(s); } } //运行到这里,就是搜不着,无解。 }
加入可行性剪枝进行优化。如果不优化不一定能 AC。
写搜索时应该先从朴素算法入手,逐步优化,以降低复杂度、减少不必要的失误。
如果不能套用,先写暴搜,命名为#0 版本。
更多的调试技巧参见老刘书上 P113 页。迭代加深搜索参见 P112。
bool mycmp(type_A,type_B){return a
2.桶排序
int bucket[1001],i,j,x,n;
memset(bucket,0,sizeof(bucket));
cin>>n;//输入一个数 n,表示接下来有 n 个数
for(i=1;i<=n;i++){
cin>>x; //把每一个数读到变量 x 中
bucket[x]++; //进行计数,对编号为 t 的桶放一个小旗子
}
for(i=1000;i>=0;i--){ //这里枚举的是数的范围。
for(j=1;j<=bucket[i];j++){ //出现了几次就将桶的编号打印几次
cout<
3. 快速排序(分治,重在理解)
void quicksort(int start,int end){
int low=start,high=end,check=a[(start+end)/2];
//划分,把比 check 小的数放它的左边,大的放右边。
while(low<=high){
while(a[low]check && low<=high) high--;//在右端找到第一个比 check 小的数。
if(low<=high){
swap(a[low],a[high]);
low++;high--;
}
}
if(high>start) quicksort(start,high);
if(low>n;
for(int i=1;i<=n;i++) cin>>a[i];
quicksort(1,n);
for(int i=1;i<=n;i++) cout<
更多的不常用排序方法,参见老刘书 P17。
3. 分治
1.快速幂
给你三个整数 ,求(b^p)%k 的值。
long long b,p,k,ans=1;
cin>>b>>p>>k;
while(p>0){
if(p%2!=0) ans=ans*b%k;//如果 p 为单数,乘到 ans 里面去,然后取模
b=b*b%k;//每次运算都取模
p=p/2;
}
ans=ans%k;//在 p = 0 时有取模
cout<
2.二分查找
int find(int x){
int left=1,right=n,mid=(left+right)/2;//左边界,右边界,二分中间点
while(left+1x) right=mid;//如果在左半部分
}
if(a[left]==x) return left;
if(a[left]==x) return right;
return -1;//没有找到。
}
3.二分答案
这个算法比较难以理解,推荐博客 。
例如:求最小值
int binary(){
int l=0, r=n, mid;
while(l < r){
mid = (l + r) /2;
if(check(mid)) r = mid; //大多数题只要改改 check()即可
else l = mid + 1;
}
return l;
}
二分答案与二分查找类似,即对有着单调性的答案进行二分, 大多数情况下用于求解满足
某种条件下的最大(小)值。
4. 数学
①.组合数学基础
加法原理:在第 n 类办法中有풎풏种不同的方法,那么完成这件事有 N=m1…+ 풎풏种方法。(分类)
乘法原理:做一件事完成有 n 个步骤,做第 n 种有풎풏种不同方法。有 N=m1*…풎풏 种方法。(分步)
排列:从 n 个不同元素中,任取 m 个元素,按照一定的顺序排成一列。(元素有序)
当
n
=
m
n=m
n=m时为全排列,方案数为
n
!
n!
n!
组合:从 n 个不同元素中,任选 m 个元素并成一组,叫从 n 个不同元素中取出 m 个元素的一个组合。
注意代码要先乘后除,避免出现小数。for(int i=1;i<=n;i++) c[i]=c[i-1]*(n-i+1)
应用:
(1)隔板法(2)插空法(3)捆绑法(4)圆排列(5)错排(6)容斥原理(重要)
具体用法请自己查询,由于编者手头有一本《进阶指南》,上面有全的。在这里不过多阐述。
②数位相关
1.统计数字位数。
int cont(int n){ //统计 n 的位数
int sum=0;
while(n>0){
sum++;
n=n/10;
}
return sum;
}
2.统计 n 的数字和
int sum(int n){ //统计 n 的数字和
int sum=0;
while(n>0){
sum=sum+n%10;
n=n/10;
}
return sum;
}
3.计算 n 的逆序数
int rev(int n){ //计算 n 的逆序数
int sum=0;
while(n>0){
sum=sum*10+n%10;
n=n/10;
}
return sum;
}
4.判断 n 是否为回文数
bool pal(int n){ //判断是否是回文数
int sum=0,m=n;
while(n>0){
sum=sum*10+n%10;
n=n/10;
}
return sum==m;
}
5.判断 n 在 b 进制下是不是回文数
bool pal(int n,int b){
int sum=0,m=n;
while(n>0){
sum=sum*b+n%b;
n=n/b;
}
return sum==m;
}
③进制相关
十进制转二进制:
//十进制转二进制->将数字%2,余数存在数组里然后将这些数字除 2,重复,直到数字大于 0
for(i=0;n>0;i++){
a[i]=n%2;
n=n/2;
}
for(i=i-1;i>=0;i--) cout<
二进制转十进制,则是反过来:
int n,ans=0,m,k=0;
cin>>n;
while(n!=0){
m=n%10;
n=n/10;
ans=ans+m*pow(2,k++);
}
cout< 


