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
本题思路
基本思路就是列举最后一层的数据,然后在最后一层确定的基础上,按照规则模拟,如果可行放入set中(可以去重),最后输出set的长度就是答案
dfs这题可以用dfs直接暴力出来,主要问题其实是在于突破题意,如果按照常规,我们放入数组,然后一个个组合,这样时间耗时是巨大的,所以我们通过题意可以发现,其实每一点的状态就两种A or B那么其实我们对每一位只要模拟两次,这样就很快了,然后就是其实确认的最后一层其实就确认了整个机器人塔,也就是我们去重的时候只存最后一层即可,但是这个代码只能过83%,第四个测试点无法通过,如果发现问题欢迎留言指正。
下面上代码
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.util.HashSet;
import java.util.Set;
public class Main机器人塔 {
static int n,m,q,aa[][];
static Set<String> set=new HashSet<String>();
public static void main(String[] args) throws IOException {
StreamTokenizer x=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
PrintWriter out=new PrintWriter(System.out);
x.nextToken();
n=(int)x.nval;
x.nextToken();
m=(int)x.nval;
q=((int)Math.sqrt(1+4*2*(n+m))-1)/2;//按照等差数列和公式推出
aa=new int[q][];//动态创建数组
for(int i=0;i<q;i++)
aa[i]=new int[i+1];
dfs(n,m,0);//dfs
out.println(set.size());
out.flush();
}
public static void dfs(int a,int b,int l) {
if(l==q) {//如果达到最底层的长度那么就开始验证是否可行
if(check(a,b)) {//可行
StringBuilder sb = new StringBuilder();//放入set
for (int i = 0; i < l; i++) {
sb.append(aa[l-1][i]);
}
set.add(sb.toString());
}
return;
}
for(int i=0;i<2;i++) {
if(i==0) {//这个位置为A
aa[q-1][l]=0;
dfs(a-1,b,l+1);
}
else {//这个位置为B
aa[q-1][l]=1;
dfs(a,b-1,l+1);
}
}
}
public static boolean check(int a,int b) {
for(int i=q-2;i>=0;i--) {//开始填入
for(int j=0;j<aa[i].length;j++) {
if(aa[i+1][j]!=aa[i+1][j+1]) {//说明只能填B
if(b>0) {
aa[i][j]=1;
b--;
}
else//不满足则不能组成
return false;
}
else if(aa[i+1][j]==aa[i+1][j+1]) {//只能A
if(a>0) {
aa[i][j]=0;
a--;
}
else
return false;
}
}
}
return true;
}
}