递推与递归思想:将一个很大的任务分解成规模小一些的子任务,子任务分成更小的子任务,直到遇到初始条件,最后整理归纳解决大任务
题目一:数楼梯
对于第n阶台阶,可以由第n-1级台阶上1阶或由第n-2级台阶上2阶得到,由此得到递推式
f
[
n
]
=
f
[
n
−
1
]
+
f
[
n
−
2
]
f[n] = f[n-1]+f[n-2]
f[n]=f[n−1]+f[n−2]
初始化
f
[
1
]
=
1
,
f
[
2
]
=
2
f[1] = 1,f[2] = 2
f[1]=1,f[2]=2
代码如下:
#include <bits/stdc++.h>
using namespace std;
vector<int> add(vector<int> A,vector<int> B)
{
vector<int> C;
int t = 0;
for(int i = 0;i < A.size() || i < B.size();i++)
{
if(i < A.size())
t += A[i];
if(i < B.size())
t += B[i];
C.push_back(t%10);
t /= 10;
}
while(t)
{
C.push_back(t%10);
t /= 10;
}
return C;
}
int main()
{
int n;
cin >> n;
vector<int> a,b;
a.push_back(1);
b.push_back(2);
if(n == 0)
{
cout << "0";
return 0;
}
else if(n == 1)
{
cout << "1";
return 0;
}
else if(n == 2)
{
cout << "2" << endl;
}
else if(n > 3)
{
vector<int> ans;
for(int i = 3;i <= n;i++)
{
ans = add(a,b);//高精度加法
a = b;
b = ans;
}
for(int i = ans.size()-1;i >= 0;i--)
{
cout << ans[i];
}
}
return 0;
}
题目二:过河卒
已知马的坐标cx,cy,则通过dx[9] = {0,2,1,-1,-2,-2,-1,1,2} ,dy[9] = {0,1,2,2,1,-1,-2,-2,-1}得到马可以到达的点,而这些点是卒不可以到的点,并且卒只可以向右走或向下走,于是得到递推式
f
[
i
]
[
j
]
=
f
[
i
−
1
]
[
j
]
+
f
[
i
]
[
j
−
1
]
f[i][j] = f[i-1][j]+f[i][j-1]
f[i][j]=f[i−1][j]+f[i][j−1]
代码如下:
#include <bits/stdc++.h>
using namespace std;
const int N = 40;
long long a[N][N];
bool flag[N][N];
int dx[9] = {0,-2,-1,1,2,2,1,-1,-2};
int dy[9] = {0,1,2,2,1,-1,-2,-2,-1};
int main()
{
int cx,cy;
int bx,by;
cin >> bx >> by >> cx >> cy;
bx += 2;
by += 2;
cx += 2;
cy += 2;//防止出现负数使得数组越界
a[2][1] = 1;
for(int i = 0;i <= 8;i++)
flag[cx+dx[i]][cy+dy[i]] = true;
for(int i = 2;i <= bx;i++)
{
for(int j = 2;j <= by;j++)
{
if(flag[i][j])
continue;
a[i][j] = a[i-1][j]+a[i][j-1];
}
}
cout << a[bx][by];
return 0;
}
题目三:栈
也就是一个由队列进入到栈中,同时栈中数字出栈的过程
对于数组
f
[
N
]
[
N
]
f[N][N]
f[N][N],i已经出栈的数字个数,j表示进栈的数字个数,
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示方案数
初始化:在出栈数为0时,对于已入栈的数字只有一种输出方案
递推式:
(1)如果当前栈内已空
(
i
=
=
j
,
出栈数
=
=
入栈数
)
(i == j,出栈数 == 入栈数)
(i==j,出栈数==入栈数)则下一步只能入栈,当前的方案数与出栈数为i-1时相同
f
[
i
]
[
j
]
=
f
[
i
−
1
]
[
j
]
f[i][j] = f[i-1][j]
f[i][j]=f[i−1][j]
(2)如果当前栈非空
(
i
<
j
,
出栈数
<
入栈数)
(i < j,出栈数 < 入栈数)
(i<j,出栈数<入栈数)则此时既可以入栈也可以出栈,
f
[
i
]
[
j
]
=
f
[
i
−
1
]
[
j
]
+
f
[
i
]
[
j
−
1
]
f[i][j] = f[i-1][j]+f[i][j-1]
f[i][j]=f[i−1][j]+f[i][j−1]
(或者用卡特兰数,暂时还不会)
代码如下:
#include <bits/stdc++.h>
using namespace std;
const int N = 30;
long long f[N][N]; //i个出栈,j个进栈
int main()
{
int n;
cin >> n;
for(int i = 0;i <= n;i++)
{
f[0][i] = 1;
}
for(int i = 1;i <= n;i++)
{
for(int j = i;j <= n;j++)
{
if(i == j)
f[i][j] = f[i-1][j];
else
f[i][j] = f[i-1][j] + f[i][j-1];
}
}
cout << f[n][n];
return 0;
}
题目四:数的计算
求合法数列,已6为例
6
6,1
6,2
6,3
6,2,1
6,3,1
可以发现对于数n,其可行的方案数为所有
<
=
n
/
2
<=n/2
<=n/2的方案数之和
代码如下:
#include <bits/stdc++.h>
using namespace std;
const int N = 1010;
long long f[N];
int main()
{
int n;
cin >> n;
for(int i = 1;i <= n;i++)
{
f[i]++;//至少有一个就是自己本身
for(int j = 1;j <= i/2;j++)
{
f[i] += f[j];
}
}
cout << f[n];
return 0;
}
题目五:Function
即按照题目要求实现递归函数
w
(
a
,
b
,
c
)
w(a,b,c)
w(a,b,c)
代码如下:
#include <bits/stdc++.h>
using namespace std;
long long ans = 0;
const int N = 30;
long long all[N][N][N];
long long w(int a,int b,int c)
{
if(a <= 0 || b <= 0 || c <= 0)
return 1;
if(a > 20 || b > 20 || c > 20)
return w(20,20,20);
if(a < b && b < c)
{
if(all[a][b][c-1] == 0)
{
all[a][b][c-1] = w(a,b,c-1);
}
if(all[a][b-1][c-1] == 0)
{
all[a][b-1][c-1] = w(a,b-1,c-1);
}
if(all[a][b-1][c] == 0)
{
all[a][b-1][c] = w(a,b-1,c);
}
all[a][b][c] = all[a][b][c-1] + all[a][b-1][c-1] - all[a][b-1][c];
}
else
{
if(all[a-1][b][c] == 0)
{
all[a-1][b][c] = w(a-1, b, c);
}
if(all[a-1][b-1][c] == 0)
{
all[a-1][b-1][c] = w(a-1, b-1 ,c);
}
if(all[a-1][b][c-1] == 0)
{
all[a-1][b][c-1] = w(a-1, b, c-1);
}
if(all[a-1][b-1][c-1] == 0)
{
all[a-1][b-1][c-1] = w(a-1, b-1, c-1);
}
all[a][b][c] = all[a-1][b][c] + all[a-1][b][c-1] + all[a-1][b-1][c] - all[a-1][b-1][c-1];
}
return all[a][b][c];
}
int main()
{
int a,b,c;
while(true)
{
cin >> a >> b >> c;
if(a == b && b == c && a == -1)
break;
cout << "w(" << a << ", " << b << ", " << c << ") = " << w(a,b,c) << endl;
}
return 0;
}