*点击

[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;
}

 

 

 

posted @ 2020-08-25 08:51  木偶人-怪咖  阅读(242)  评论(0编辑  收藏  举报
*访客位置3D地图 *目录