方格填数蓝桥杯 c语言,第七届蓝桥杯省赛--方格填数--DFS

答案是 1580

思路

一共10个位置  10个数

第一个位置 可以放0-9   接下来的位置要满足相邻位置不连续   所以我们dfs搜索所有可能的方案并计数

我们先建立坐标  如图所示

然后 我们DFS的方向需要注意一下

这个题的解法巧妙就在于我们 DFS的顺序

我们按照从左到右的方向去DFS

走到最右边的时候  我们不往下走   而是另起一行 继续从左往右   如图

为什么这么做呢 ?

这样做可以大大降低DFS的复杂度   好处如下(可以结合代码去看比较好理解)

1、我们DFS的时候 可以有四个探测方向  但是按照这样做就只有向右探测一个方向了  到头了就另起一行

2、依据题意  我们在给一个位置放数字的时候 需要判断他的八个方向  看看相邻数字是否连续  但是我们用这种顺序去DFS就只用判断四个方向  左  左上  上  右上  因为按照这个顺序去填数  所填位置的下边和右边还没到呢  所以不用考虑下(左下  右下  正下)和右

3、注意开头和结尾  (0,0)和(2,3)这两个位置是不能填数的   那么你判断边界的时候怎么判断呢  如果你以0<=x<=2 和0<=y<=3来判断呢是无法判断到(0,0)和(2,3)的  需要特判 ,而我们用这种dfs顺序呢,我们不需要特判。开头我们直接从(0,1)开始,避过了(0,0)。而结尾(2,3)刚好说明我们填数结束了,此时计数顺便结束递归就好了

ps:两个小细节

1、往左走是 (x,y-1)  左上走是(x-1,y-1)  正上是(x-1,y)  所以我们用一个转向数组,

int dir[4][2]={{0,-1},{-1,-1},{-1,0},{-1,1}};//x y分别加上 就代表左 左上 上 右上

2、要求数字不连续  我们直接判断差的绝对值大于一就好了

代码 及注释

#include

#include

#include

#include

#include

using namespace std;

int a[4][4];

int vis[11];

int cnt=0;

bool check(int x,int y,int v){

//转向

int dir[4][2]={{0,-1},{-1,-1},{-1,0},{-1,1}};//左 左上 上 右上

for(int i=0;i<4;i++){

int xx=x+dir[i][0];

int yy=y+dir[i][1];

if(xx<3 && xx>=0 && yy<4 && yy>=0){

if(abs(a[xx][yy]-v)==1)return false;

}

}

return true;

}

void DFS(int x,int y){

if(x==2&&y==3){cnt++;return;}//遇到(2,3)说明结束

for(int i=0;i<=9;i++){

//要确保这个数没被选过并且放在这里符合题意

if(vis[i]==0&&check(x,y,i)){

vis[i]=1;a[x][y]=i;

if(y+1<4) DFS(x,y+1);//向右搜索

else DFS(x+1,0);//另起一行

vis[i]=0;

}

}

return ;

}

int main(){

for(int i=0;i<4;i++)//初始化一个较小的数

for(int j=0;j<4;j++)

a[i][j]=-20;

DFS(0,1);//从(0,1)开始

printf("%d\n",cnt);

return 0;

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值