X星球的机器人表演拉拉队有两种服装,A和B。
他们这次表演的是搭机器人塔。
类似:
A
B B
A B A
A A B B
B B B A B
A B A B B A
队内的组塔规则是:
A 只能站在 AA 或 BB 的肩上。
B 只能站在 AB 或 BA 的肩上。
你的任务是帮助拉拉队计算一下,在给定A与B的人数时,可以组成多少种花样的塔。
输入一行两个整数 M 和 N,空格分开(0<M,N<500),分别表示A、B的人数,保证人数合理性。
要求输出一个整数,表示可以产生的花样种数。
例如:
用户输入:
1 2
程序应该输出:
3
再例如:
用户输入:
3 3
程序应该输出:
4
解题思路:根据题目我们可以发现,要想拼成一个完整的塔,必须保证A和B都要用完,而上面的服装类型都是根据下面的服装类型决定的,于是我们只需要搜索最下面一层塔的所有服装情况的全排列,在这个基础上建立塔,每使用一个A或B相应的服装数量减少,如果在建立途中就已经用完了A或B说明这种方案不可行,直接剪掉,也就是我们说的剪枝。搜索完所有方案便能得出最终结果。
这里我用二维整型数组a存储塔,1表示A,2表示B
#include <bits/stdc++.h>
using namespace std;
int map1[1001],a[501][501],N,M,n,A,B,ans=0;//map1表示映射 根据A和B的和能算出对应的最下面一层是多少
void dfs(int step)//表示最后一层的第step列
{ int i,j;
if(A<0||B<0) return ; //如果建立过程中就已经消耗完其中一种 直接剪枝
else
if(step>map1[n])//如果排列完
{ int a1=A,b1=B;//a1,b1表示剩余A和B的数量,防止后面建塔不满足跳出后影响到原来的A和B值
for(i=map1[n]-1;i>=1;i--)//开始根据最下面一层建塔
{ for(j=1;j<=i;j++)
{
if(a[i+1][j+1]==a[i+1][j])//A只能放在两个相同的上面
{ a[i][j]=1; a1--;
}
else //B只能放在两个不同的上面
{ a[i][j]=2;b1--;
}
if(a1<0||b1<0) return ;//如果建立过程中就已经消耗完其中一种 直接剪枝
}
}
ans++;//塔已建成 ,方案数+1
return ;
}
else
{
a[map1[n]][step]=1;//这一列建A
A--; //对应数量-1
dfs(step+1);//搜索下一列
A++; //回溯
a[map1[n]][step]=2;//这一列建B
B--;//对应数量-1
dfs(step+1);//搜索下一列
B++;//回溯
}
}
int main()
{
cin>>M>>N;
n=M+N; //总数
A=M; //A的数量
B=N; //B的数量
int i,t;
map1[1]=1,t=1;
for(i=2;i<=500;i++)//算出映射数组 便可得到最下面一层有多少个
{ t=t+i;
map1[t]=i;
}
dfs(1);//开始全排列最下面一层
printf("%d",ans);
return 0;
}