走道铺砖问题
注明:本题貌似不是弱化版
Description
有一个m行n列的矩阵,用1*2的骨牌(可横放或竖放)完全覆盖,骨牌不能重叠,有多少种不同的覆盖的方法?你只
需要求出覆盖方法总数的值即可。
Input
三个整数数n,m
n<=10
Output
一个整数:总数
Sample Input
7 2
Sample Output
21
铺一块砖一共有两种情况,要么横着放,要么竖着放,而横着放始终就在那一行,不会影响到上下两行,可是竖着放就会影响到上下两行,而在这里我们先假设在上面的行已经被排列好了,所以竖着放就只会影响到下面的行。那么可视化我们过一会再讲,我们先来捋一捋思路:
- 用dp[i][j]表示第i行状态为j的方案数,那么dp[n][2^m-1]就是答案。
2.非法情况:
1)例如第i行第k位已经是0,那么i-1行对应位一定是1,否则非法。如果合法继续检测(i,k+1)。
2)(i,k)=1,那么继续分类:
3)(i-1,k)=0,合法,继续检测(i,k+1)。
4)(i-1,k)=1,则只可能是(i,k+1)=(i-1,k+1)=1,否则非法。如果合法继续检测(i,k+2)。
3.对于第一行:
1)(0,k)=0,继续检测(0,k+1)。
2)(0,k)=1,则(0,k+1)=1,继续检测(0,k+2)。
4.任意需要检测(0,k+2)且k==m-1的情况,都是非法的.
嗯~ o( ̄▽ ̄)o,有图有真相,我们就以5,2为例,主要还是因为好写,像那些算出来就是36,34什么的,太多了,写不完TT(答案是8)
如图
首先我们以横为先
那么,这下面一共有多少种呢
我们可以一排横下去 呸,这是一个信息人该有的吗,我们应该说,你看,下一行该用横还是竖……好吧,分支,先用横(其实刚刚的第一行也是一个横竖的选择)
再下去仍然是一个选择,横或竖,我们继续选竖:
好的,可以继续选横:
在这里我们将会面临一个选择(一般来讲,无法实现的状态仅存于两数之中有一数为奇数的情况,因为两数均为奇数就可以输出0了O(∩_∩)O),你是选横呢还是选竖呢?
有些同学说,It’s so easy!你眼瞎吗,下面没了,只能横着啊,那你觉得计算机看得见吗?它确实眼瞎,我们不可能去给他建模,自带边界判定bug,所以我们只能手动判断。得出这里只有一种情况:横
错误情况:
好的擦掉不说了。这里就有一个DFS的特征(绝大部分情况):搜到底之后返回,那么我们返回至上一层
由于我们刚刚已经检测了横的情况,现在来看竖:
由于竖着是(二4)与(二5)没有其他的办法了,所有只能竖着,当然电脑还是需要去判断一次边界。好的,剩下的大家自己去算吧。
如果你仍然没有听懂,请点击
所有接解情况:
题解奉上:
#include<bits/stdc++.h>
using namespace std;
int x,y,ans=0;
bool used[20][20];
void find(int xx,int yy)
{
if(xx==x+1)
{
ans++;
return;
}
if(used[xx][yy]==false)
{
if(yy==y)
find(xx+1,1);
else
find(xx,yy+1);
}
if(used[xx][yy]==true)
{
if(yy<y && used[xx][yy+1]==true)
{
used[xx][yy]=false;
used[xx][yy+1]=false;
if(yy+1==y)
find(xx+1,1);
else
find(xx,yy+2);
used[xx][yy+1]=true;
used[xx][yy]=true;
}
if(xx<x && used[xx+1][yy]==true)
{
used[xx+1][yy]=false;
used[xx][yy]=false;
if(yy==y)
find(xx+1,1);
else
find(xx,yy+1);
used[xx+1][yy]=true;
used[xx][yy]=true;
}
}
}
int main()
{
cin>>x>>y;
memset(used,true,sizeof(used));
find(1,1);
cout<<ans;
}
注:memset是指将一定范围内的数赋为一定的值,就像这里就是将used与true赋为used的长度