问题描述
题目
有一个方格型的命运矩阵,矩阵边界在无穷远处。我们做如下假设:
1. 每一个格子象征林克命运中的一次抉择,每次只能从相邻的方格中做选择。
2. 从某个格子出发,只能从当前方格移动一格,走到某个相邻的方格上;
3.选择一旦做出就不可更改,因此走过的格子无法走第二次。
4. 从命运矩阵的第1行出发,只能向下、左、右三个方向走;
请问:如果最高允许在方格矩阵上走n步(也就是林克一生最多能做n个选择)。
那么随着n的不同,请问一共会有多少种不同选择的方案导致多少个不同的林克?
注意,2种走法只要有一步不一样,即被认为是不同的方案。
输入
允许在方格上行走的步数n(n <= 20)
样例
20
输出
经过n个选择之后,诞生的不同的林克的个数。
样例
54608393
思路
我们注意到,向下走的选择正好像树状展开,每走一步树就延展一层,当全部延展完后,最末端的分支的数量就是不同方案的数量。
又因为不能走走过的路,所以我们发现上一步向下走的,这一步可以向下、左、右三个方向走,但如果上一步向左走,这一步就不能向右走,同理,上一步向右走,这一步就不能向左走。我们发现不同的分支可以延展出的分支的数量是不同的。
所以我们用cnt来标记目前分支末端的数量,用mark来标记只能延展两个分支的分支,每次走一步时,分支末端数量就变为(cnt-mark)*3+mark*2,其中,没被mark的分支可以延展两个被mark的分支,被mark的分支可以延展一个被mark的分支。我们用tmp记录走这一步之前的cnt的值,则走完这一步后mark的分支的数量就会变为mark+(tmp-mark)*2。
这种方法是通过找规律得来的,因为题目只要求最后可能的数量,不要求每次走的方向。该方法代码量较少,但不易理解,利用广搜会比较好理解,但代码量会上升。
代码实现和分析
#include<iostream>
using namespace std;
int main() {
int n, cnt = 1;//走零步,只有一种可能
cin >> n;
int mark = 0;//一开始的那步可以向三个方向走,没有被mark
for (int i = 0; i < n; i++) {//走n步
int tmp = cnt;//存储走这一步之前分支末端的数量
cnt = cnt * 3 -mark;//相当于(cnt-mark)*3+mark*2,
//被mark的分支生长出两个分支,没有被mark的分支会生长出三个分支
mark = mark + (tmp - mark) * 2;//被mark的分支会生长出一个被mark的分支,
//而没有被mark的分支会生长出两个没有被mark的分支
}
cout << cnt;
}