走道铺砖问题

知识共享许可协议 版权声明:署名,允许他人基于本文进行创作,且必须基于与原先许可协议相同的许可协议分发本文 (Creative Commons

走道铺砖问题

注明:本题貌似不是弱化版

Description
有一个m行n列的矩阵,用1*2的骨牌(可横放或竖放)完全覆盖,骨牌不能重叠,有多少种不同的覆盖的方法?你只
需要求出覆盖方法总数的值即可。
Input
三个整数数n,m
n<=10
Output
一个整数:总数
Sample Input
7 2
Sample Output
21
铺一块砖一共有两种情况,要么横着放,要么竖着放,而横着放始终就在那一行,不会影响到上下两行,可是竖着放就会影响到上下两行,而在这里我们先假设在上面的行已经被排列好了,所以竖着放就只会影响到下面的行。那么可视化我们过一会再讲,我们先来捋一捋思路:

  1. 用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的长度

猜你喜欢

转载自blog.csdn.net/Tangwan_jeff/article/details/95022922