机器人塔
X星球的机器人表演拉拉队有两种服装,A和B。 他们这次表演的是搭机器人塔。
类似:
A
B B
A B A
A A B B
B B B A B
A B A B B A
- 1
- 2
- 3
- 4
- 5
- 6
队内的组塔规则是:
A 只能站在 AA 或 BB 的肩上。 B 只能站在 AB 或 BA 的肩上。你的任务是帮助拉拉队计算一下,在给定A与B的人数时,可以组成多少种花样的塔。
输入一行两个整数 M 和 N,空格分开(0<M,N<500),分别表示A、B的人数,保证人数合理性。
要求输出一个整数,表示可以产生的花样种数。
例如: 用户输入: 1 2
程序应该输出: 3
再例如:; 用户输入: 3 3
程序应该输出: 4
资源约定: 峰值内存消耗 < 256M CPU消耗 < 1000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意: main函数需要返回0 注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。 注意:
所有依赖的函数必须明确地在源文件中 #include , 不能通过工程设置而省略常用头文件。提交时,注意选择所期望的编译器类型。
网上关于这道题这种的题解不多,然后因为蓝桥练习系统里没找到这道题所以以下代码未AC,算是记录一下思路
然后这个题感觉有点理解性的歧义,是在尽可能最大的三角堆的前提下还是说小堆小堆的组合也算?
不是很清楚,不过的代码是在最大的三角堆下形成的排列
这种塔型很容易就想到满二叉树,而完全二叉树有一个很好的特性就是,父节点是i,则左儿子是2i,右儿子是(2i+1)
可以通过这个来检验合法性或者填元素
塔作为一个三角堆,同时也可以向下分成多个三角堆,以下代码是从三角形的头头开始往下填元素。
#include<iostream>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<stack>
#include<fstream>
#include<algorithm>
#include<sstream>
using namespace std;
int num=0;//记录方案数
char list[1005];//用来存储数字
//深度优先的试探
void dfs(char top,int Anum,int Bnum,int cur,int maxs,int& size){//top表示一个小三角的顶端元素 ,Anum和Bnum分别为A和B的剩余个数 ,cur表示当前坐标,maxs表示最大能填的元素个数同时也算数组的假定边界,size表示已填的元素个数
//此处的size用的是引用,因为当程序结束下层递归回退回来是,size不应该回退,毕竟下面的元素已经填充了,不过这里也可以吧size放到函数的外面,而不用作为一个参数
if(Bnum<0||Anum<0||cur>maxs)return;//当A或B元素小于0或者试探的位置越界时就不再往下试探
list[cur]=top;//将元素填充到一个位置
size++;//因此个数就加了一个
if(size==maxs){//如果元素个数等于最大元素数表示这个时候已经填完,一种排列完成
num++;
for(int i=1;i<=maxs;i++)cout<<list[i]<<" ";
cout<<endl;
return ;
}
if(top=='A'){//如果顶端元素是A,则其左右儿子可以是AA或BB
int si = size;//保存当前个数
dfs('A',Anum-1,Bnum,cur*2,maxs,size);//递归左儿子 ,因为父节点用了一个A,所以是Anum-1
dfs('A',Anum-2,Bnum,cur*2+1,maxs,size);//递归右儿子 ,因为左儿子用了一个A,所以这里就是Anum-2,
int newSize = size;//保留一下添加AA后的size,用于下面的size的恢复
size = si;//因为AA和BB是完整的两个选择分支,使用此处的size应该和试探过AA前的size相同,因为试探过AA则size很可能发生改变
dfs('B',Anum,Bnum-1,cur*2,maxs,size);
dfs('B',Anum,Bnum-2,cur*2+1,maxs,size);
if(si==size&&cur*2<maxs)size=newSize;//试探过BB而size没变化表示填充BB失败, 所以恢复原来AA后的size值,应当注意叶子节点的试探是无意义的使用它造成的size不变应该不作为恢复size值的依据
}
else if(top=='B'){
int si = size;
dfs('A',Anum-1,Bnum,cur*2,maxs,size);
dfs('B',Anum,Bnum-1,cur*2+1,maxs,size);
int dif = size-si;
size = si;
dfs('B',Anum,Bnum-1,cur*2,maxs,size);
dfs('A',Anum-1,Bnum,cur*2+1,maxs,size);
if(si==size&&cur*2<maxs)size=size+dif;
}
return;
}
int main(){
int m,n;
cin>>m>>n;
string line="";
int h =log(m+n+1)/log(2);//计算最大层数
int maxs = pow(2,h)-1;//计算此层数下的元素值
int i=0;
dfs('A',m-1,n,1,maxs,i);//顶底为A时的排列数
i=0;
dfs('B',m,n-1,1,maxs,i);//顶底为B时的排列数
cout<<num;
return 0;
}
除题目给出的测试用例外
比如
15 1 --> 1 //像这样(Anum>15,Bnum<2)的情况下,可以很明显的看出这个时候只有一种组合就是全A,不过网上很多答案对这类输入的结果0
除此外其他的也不好验证了,毕竟3层之后的组合我也推不出来了......