题目:小兵向前冲
题目描述:N*M的棋盘上,小兵要从左下角走到右上角,只能向上或则向右走,问由多少种走法。
- 套路:计数问题
- 暴力搜索(回溯法)
- F(n,m)表示棋盘大小为n*m时走法数量
- F ( n , m ) = F ( n , m − 1 ) + F ( n − 1 , m ) i f n ∗ m > 0 , o t h e r w i s e F ( n , m ) = 1 F(n,m) = F(n,m-1) + F(n-1,m) ~if ~n*m >0,otherwise~ F(n,m) = 1 F(n,m)=F(n,m−1)+F(n−1,m) if n∗m>0,otherwise F(n,m)=1
-
f
o
r
i
<
−
2
t
o
n
for~~i<-~ ~2~~ to~n
for i<− 2 to n
- f o r j < − 2 t o m for~~ j<-~~2 ~~to ~~m for j<− 2 to m
#include <iostream>
using namespace std;
int forward(int n, int m)
{
if (n == 0 || m == 0)
{ //棋盘都没有走啥?
return 0;
}
if (n == 1 || m == 1) //条状棋盘
{
return 1;
}
return forward(n, m - 1) + forward(n - 1, m); //4*4 <-- 4*3 || 3*4
}
int main()
{
cout<<forward(2,3);
return 0;
}
要是小兵可以走两步呢?
修改代码:
return forward(n, m - 1) + forward(n - 1, m) +
forward(n, m - 2) + forward(n - 2, m);
//4*4 <-- 4*3 || 3*4 || 4*2 ||2*4
拓展
组合数的递推公式
C
(
n
,
m
)
=
C
(
n
−
1
,
m
−
1
)
+
C
(
n
−
1
,
m
)
C(n,m) = C(n-1,m-1) + C(n-1,m)
C(n,m)=C(n−1,m−1)+C(n−1,m)
#include <iostream>
using namespace std;
int nCr(int n, int m) //组合数
{
if(n < m){
return 0;
}
if (m == 0)
{
return 1;
}
return nCr(n-1,m-1) + nCr(n-1,m);
}
int main()
{
cout << nCr(3,2);
return 0;
}
可以类比于棋盘,只可以往右上角走或者往上走,问有多种解法。这就是组合数的物理意义。要是(n,m)这个格子不能走呢?那直接让 F ( n , m ) = 0 F(n,m)=0 F(n,m)=0。