题目描述
有一个长为a,宽为b的矩形(1≤a≤6,2≤b≤6)。可以把这个矩形看作是a*b个小方格。
我们现在接到了这样的一个任务:请你计算出,把这个矩形分割成两个部分的方法总数。
你不是可以任意地分割这个大的矩形, 必须满足:
分割后,每个部分,至少各自均有一个方格是在大矩形的最外边上(即大矩形最外面一环的方格)。
输入输出格式
输入格式:
输入文件仅包含两个数字,a和b。
输出格式:
输出仅有1行,这一行仅有一个整数,表示分割的方案总数。
输入输出样例
输入样例#1:
3 2
输出样例#1:
15
看到这题,我十分的束手无策,但是当我认真看完题目之后,发现了
(1<=a,b<=6)
这就为暴力提供了很好的机会
我们可以把这个矩阵想象成一个无向图,然后就是求从一个边界点 出发(不走边界点)到另外一个边界点的方案数
但是这样可能行不通,因为你很难判断这个方案是否走过,我一开始想用状态压缩来判断这种方案是否出现过,后来发现没有这个必要
我们只需要从矩阵一条长和一条宽上的每个点出发,求出到另外一个边界点的方案数,记得不要从矩阵的端点出发
#include<cstdio>
#include<cstring>
using namespace std;
const int N=1e1;
int n,m;
int ans=0;
int dx[4]={-1,0,1,0};//上下左右四个方向
int dy[4]={0,1,0,-1};
bool map[N][N];//map判断这个点有没有走过
void dfs(int x,int y)
{
map[x][y]=1;//把这个点设置为走过
if(x==1||y==m||x==n||y==1){//如果到了边界点
ans++;
map[x][y]=0;
return;
}
for(int i=0;i<4;++i){//往四个方向搜索
int xx=x+dx[i],yy=y+dy[i];
if(xx<1||yy<1||xx>n||yy>m||map[xx][yy])continue;
dfs(xx,yy);
}
map[x][y]=0;//回溯
}
int main() {
scanf("%d%d",&n,&m);
n++;m++;//要多加一个点
memset(map,0,sizeof(map));//初始化所有的点都是可以走的
for(int i=2;i<n;++i){
map[i][1]=1;//把这个点设置为不能走
dfs(i,2);//直接从下一个点开始搜索,保证不会走边界
map[i][1]=0;//回溯
}
for(int i=2;i<m;++i){//同上
map[1][i]=1;
dfs(2,i);
map[1][i]=0;
}
printf("%d\n",ans);//输出
return 0;
}
好了,文章就到这里了
其实,我一开始想这个代码的时候发现了一个似乎存在的bug
那就是我从//(x,y)表示(行,列)
(1,2)->(2,2)->(2,1)
和
(2,1)->(2,2)->(1,2)
不是一样的吗,为什么这样可行?
这个问题让你们自己去想!!!
提示:
只从两条边开始搜索