蓝桥杯 机器人塔

机器人塔

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层之后的组合我也推不出来了......

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值