[CQOI2007]矩形
题目
Description
给一个a*b矩形,由a*b个单位正方形组成。你需要沿着网格线把它分成非空的两部分,每部分所有格子连通,且至少有一个格子在原矩形的边界上。“连通”是指任两个格子都可以通过水平或者竖直路径连在一起。 求方案总数。例如3*2的矩形有15种方案。
Input
输入仅一行,为两个整数a,b。 1<=a<=6, 2<=b<=7
Output
输出仅一行,即方案总数。
Sample Input
3 2
Sample Output
15
思路
这一题我们可以搜索;
搜索每一条分割线,分割线一般从$(0,0)$ 到 $(n,m)$ ;
分割线$(0,0)$ 表示坐标 $(1,1)$ 的左上角那个点;
这样我们就可以搜索每一条分割线;
枚举每条分割线的起点 $i$;
题目要求至少有一个格子在原矩形的边界上,所以 $i$ 的范围必须满足 $1 \leq i \leq n$ 或 $m$ ;
这样每一块都会有一个点在矩形的边界上了;
那么找到答案的情况就是,分割线到了边界就,$ans++$ ;
分割线起点在左边第一排的每次就 $dfs(i,1)$ ;
分割线坐标的起点要保证不在边界上;
还要注意的是,不能让分割线在当前排往回走,
也就是,在$dfs$ 之前要记录 $f[i][0]=1$ 表示不能走,分割线是从 $1$ 到 $m$, 所以不能让它从 $1$ 到 $0$ ;
这样就 $ok$ 了;
代码
#include<bits/stdc++.h> #define re register typedef long long ll; using namespace std; inline ll read() { ll a=0,f=1; char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();} while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();} return a*f; } ll n,m; ll a[5]={0,1,0,-1,0}; ll b[5]={0,0,1,0,-1}; ll f[10][10]; ll ans,num; inline void dfs(ll x,ll y) { if(x<1||x>=n||y<1||y>=m)//如果分割线枚举到了边界 { ans++;//答案加一 return; } for(re ll i=1;i<=4;i++)//不断的找 { ll xx=x+a[i],yy=y+b[i]; if(f[xx][yy]==num)//分割线不能重合,所以当前点不能被走过 continue; f[xx][yy]=num; dfs(xx,yy); f[xx][yy]=0;//回溯 } } int main() { n=read(); m=read();//读入 //横着找一遍 for(re ll i=1;i<n;i++)//枚举,横坐标不能在边界上 { num++;//一个不需要用memset,的小小优化 f[i][0]=num;//不能回到在当前行左边的边界 //分割线是从 1到 m ,所以不能让它从 1 到 0 f[i][1]=num;//标记走过 dfs(i,1); } //竖着找一遍 for(re ll i=1;i<m;i++) { num++; f[0][i]=num;//不能回到在当前列上边的边界 //分割线是从 1到 n ,所以不能让它从 1 到 0 f[1][i]=num;//标记走过 dfs(1,i); } printf("%lld\n",ans);//输出答案 //return 0; }