蒙德里安的梦想
求把NM的棋盘分割成若干个12的的长方形,有多少种方案。
例如当N=2,M=4时,共有5种方案。当N=2,M=3时,共有3种方案。
如下图所示:
输入格式
输入包含多组测试用例。
每组测试用例占一行,包含两个整数N和M。
当输入用例N=0,M=0时,表示输入终止,且该用例无需处理。
输出格式
每个测试用例输出一个结果,每个结果占一行。
数据范围
1≤N,M≤11
输入样例:
1 2
1 3
1 4
2 2
2 3
2 4
2 11
4 11
0 0
输出样例:
1
0
1
2
3
5
144
51205
分析
import java.util.Scanner;
/**
* 1. 左移运算符
* value << num 移位值(value)移动(num)位
* 左移的规则只记住一点:丢弃最高位,0补最低位
* 在数字没有溢出的前提下,对于正数和负数,左移一位都相当于乘以2的1次方,左移n位就相当于乘以2的n次方
* 2. 右移运算符
* value >> num 移位值(value)移动(num)位
* 右移的规则只记住一点:符号位不变,左边补上符号位
* 右移一位相当于除2,右移n位相当于除以2的n次方。
* 3. &与运算
* 两个操作数中位都为1,结果才为1,否则结果为0
* 4. |或运算
* 两个位只要有一个为1,那么结果就是1,否则就为0
* 5. ~非运算
* 如果位为0,结果是1,如果位为1,结果是0
*/
public class Main {
private static int N=12,M=1<
private static int n,m;//矩形的行和列
private static long[][] f=new long[N][M];//状态转移方程
private static boolean[] st=new boolean[M];//
public static void main(String[] args){
Scanner scanner=new Scanner(System.in);
while (true){
n=scanner.nextInt();
m=scanner.nextInt();
//当输入用例N=0,M=0时,表示输入终止,且该用例无需处理
if(m==0 && n==0)
break;
//预处理一下所有状态不存在连续奇数个0,所有状态是从0到1<
for(int i=0;i<1<
st[i]=true;//假设是成立的
int cnt=0;//当前这段连续0的个数
for(int j=0;j
if((i >> j & 1 )== 1){//如果当前这段是1,说明上一段已经截至了
if((cnt & 1)==1)//判断0是否有奇数个
st[i]=false;//有奇数个
cnt=0;//遇到1以后代表这段结束了,把cnt置为0
}else
cnt++;
}
if((cnt & 1) ==1 )//判断最后一段0的个数,如果是奇数,把st[i]置为false
st[i]=false;
}
//重置
for(int i=0;i
for(int j=0;j
f[i][j]=0;
}
f[0][0]=1;//最开始的时候小方块什么都没放,第0只能是1
//枚举所有的列
for(int i=1;i<=m;i++){
for(int j=0;j<1<
for(int k=0;k<1<
if(st[(j|k)]==true && (j & k)==0){
f[i][j]+=f[i-1][k];
}
}
}
}
//第 m-1 行,没有捅出任何小方格的时候
System.out.println(f[m][0]);
}
}
}