样例结果分析:
10 = 9 +1
10 = 8 + 2
10 = 7 + 3
10 = 7 + 2 + 1
10 = 6 + 4
10 = 6 + 3 + 1
10 = 5 + 4 + 1
10 = 5 + 3 + 2
10 = 4 + 3 + 2 +1
当然本题可以使用回溯法解决且难度并不是很大,只需要注意剪枝即可。下面介绍使用迭代法解决的方法。我看到这题的时候首先想到的是使用动态规划解决,但后面发现其实也像一个迭代的过程。主要是它只用前一个状态便可以得出现状态。
因为N >= 3,显然N= 3 时:只有一种搭建放方法:
2 | 1 | 0 |
现在N = 4,意味着多了一块积木,我们可以有三种选择:
放在第一层、第二层、或者他单独成为一层,即下面的情况:
3 | 1 | 0 |
2 | 2 | 0 |
2 | 1 | 1 |
显然后两种都不满足不出现相同砖数的要求,故舍去。
故N = 4的时候
3 | 1 | 0 |
N = 5时又多了一块积木,这时候我们还要N = 3的基础上进行操作吗?显然不用,同样的思路,我们针对N = 4 时的台阶采用同样的方法,添加一块积木——可以是第一层、第二层添加一层可以得到下面的表
4 | 1 | 0 |
3 | 2 | 0 |
3 | 1 | 1 |
最后一种情况不符合故舍去。
N = 5:
4 | 1 | 0 |
3 | 2 | 0 |
同理N = 6时:
5 | 1 | 0 |
4 | 2 | 0 |
4 | 1 | 1 |
4 | 2 | 0 |
3 | 3 | 0 |
3 | 2 | 1 |
这时出现了相同的结果,第一种组合的第2层加1 和 第二种组合的第1层加1得到的结果是相同的,因此这里需要一个去重的操作,此外我们还可以看到第一次出现了单独作为一层的情况
3 | 2 | 1 |
为了重复上面的相同的操作,我们必须得在后面在添加一个0,这样就能与上面的方法保持一致了即:
3 | 2 | 1 | 0 |
N = 6 且去重之后的结果:
5 | 1 | 0 | / |
4 | 2 | 0 | / |
3 | 2 | 1 | 0 |
继续迭代这个过程到N即可。
#include<iostream>
#include<vector>
using namespace std;
bool compare_ans(vector<int>num, vector<vector<int>>Ans) { // 判断是否已经有这个解
for (int i = 0; i < Ans.size(); i++) {
vector<int>temp = Ans[i];
if (num == temp) {
return false;
}
}
return true;
}
int main() {
//当前的状态只与n-1 的状态有关,用两个2维数组即可存储。
//temp 表示n -1,ans 表示n;
vector<vector<int>>temp;
vector<vector<int>>ans;
int n;
cin >> n;
ans.push_back({ 2,1,0});//初始化
for (int i = 0; i < n - 3; i++) {
temp = ans;
ans.clear();
for (int j = 0; j < temp.size(); j++) {
for (int k = 0; k < temp[j].size(); k++) {
vector<int>num;
num = temp[j];
num[k]++;
if (k == 0) {
bool judge = compare_ans(num, ans);
if (judge == 1) {
ans.push_back(num);
}
continue;
}
if (k == temp[j].size()-1) {
if (num[k] < num[k - 1]) {
//末尾舔0再进行判重
num.push_back(0);
bool judge = compare_ans(num, ans);
if(judge == 1){
ans.push_back(num);
}
continue;
}
}
if (num[k] < num[k - 1]) {
bool judge = compare_ans(num,ans);
if (judge == 1) {
ans.push_back(num);
}
continue;
}
}
}
}
cout << ans.size();
return 0;
}