第一讲 递归与递推
递归
将问题分解为若干个同种子问题
自己调用自己
所有递归都可以转化为递归搜索树来理解
斐波那契数列
int f(int n)
{
if(n == 1) return 0;
if(n == 2) return 1;
return f(n - 1) + f(n - 2);
}
指数型枚举
const int N = 16;
int n;
bool sta[N];
void dfs(int u)
{
if (u > n)
{
for (int i = 1; i <= n; i++)
{
if (sta[i])
cout << i << ' ';
}
cout << endl;
return;
}
//选
sta[u] = true;
dfs(u + 1);
sta[u] = false;
//不选
dfs(u + 1);
}
组合型枚举
const int N = 30;
int sta[N], m, n;
bool used[N];
void dfs(int u, int start)
{
if (u > n)
{
for (int i = 1; i <= n; i++)
printf("%d ", sta[i]);
puts("");
return ;
}
for (int i = start; i <= m; i++)
{
sta[u] = i;
dfs(u + 1, i + 1);
sta[u] = 0;
}
}
优化:剪枝
if(u + m - start < n)
return ;
排列型枚举
const int N = 10;
int n;
int sta[N];
bool use[N];
void dfs(int u)
{
if (u > n)
{
for (int i = 1; i <= n; i++)
cout << sta[i] << ' ';
cout << endl;
return;
}
for (int i = 1; i <= n; i++)
if (!use[i])
{
sta[u] = i;
use[i] = true;
dfs(u + 1);
sta[u] = 0;
use[i] = false;
}
}
递推
先求子问题,用子问题推原问题
斐波那契数列
int main()
{
int n;
cin >> n;
int f[46];
f[1] = 0, f[2] = 1;
for(int i = 3; i <= n; i++)
f[i] = f[i - 1] + f[i - 2];
for(int i = 1; i <= n; i++)
cout << f[i] << ' ';
return 0;
}
优化:不开数组,使用两个变量(滚动数组雏形)
int main()
{
int n;
cin >> n;
int a = 0, b = 1;
for(int i = 1; i <= n; i++)
{
cout << a << '';
int fn = a + b;
a = b, b
}
return 0;
}
习题
第二讲 二分和前缀和
二分法
整数二分
步骤:
-
找一个区间[L, R],使得答案一定在区间中
-
找一个判断条件, 使得该判断体哦阿健具有二段性,并且答案一定是改二段性的分界点。
-
分析重点M在改判断条件下是否成立,考虑在哪个区间。
-
如果更新方式是 R = M,则不用做任何处理;如果是 L= M, 则需要在计算M时加1。
模板:
-
将[l, r]划分为[l, M]和[M + 1, r]
bool check(int x) { /* 是否满足某种性质 */ } int bsearch_1(int l, int r) { while(l < r) { int M = l + r >> 1; //右移 if(check(M)) r = M; else l = M + 1; } return l; }
-
将[l, r]划分为[l, M - 1]和[M, r]
bool check(int x) { /* 是否满足某种性质 */ } int bsearch_2(int l, int r) { while(l < r) { int M = l + r + 1 >> 1; //右移 if(check(M)) l = M; else r = M - 1; } return l; }
实数二分
模板:
bool check(int x)
{
/*
是否满足某种性质
*/
}
int bsearch_3(double l, double r)
{
const double eps = 1e-6;
while(r - l > eps)
{
double mid = l + r >> 1;
if(check(mid)) r = mid;
else l = mid;
}
return l;
}
前缀和
对数据预处理
一维前缀和