第七届 蓝桥杯 方格填数 dfs

时间:2021-09-24 19:23:55

如下的10个格子 
第七届 蓝桥杯 方格填数 dfs 
填入0~9的数字。要求:连续的两个数字不能相邻。 (左右、上下、对角都算相邻) 
一共有多少种可能的填数方案? 
请填写表示方案数目的整数。 
注意:你提交的应该是一个整数,不要填写任何多余的内容或说明性文字。

方法一:遍历

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int map[][];
int ans=;
int Abs(int i,int j)//判断 8个方向
{
if(abs(map[i-][j]-map[i][j])==)
return ;
if(abs(map[i+][j]-map[i][j])==)
return ;
if(abs(map[i][j+]-map[i][j])==)
return ;
if(abs(map[i][j-]-map[i][j])==)
return ;
if(abs(map[i-][j-]-map[i][j])==)
return ;
if(abs(map[i+][j-]-map[i][j])==)
return ;
if(abs(map[i-][j+]-map[i][j])==)
return ;
if(abs(map[i+][j+]-map[i][j])==)
return ;
return ;
}
int f()//判断相邻的数是否连续
{
if(Abs(,)&&Abs(,)&&Abs(,)&&Abs(,)&&Abs(,)&&Abs(,))
return ;
return ;
}
int main()
{
memset(map,-,sizeof(map));
int a[] = {,,,,,,,,,};
do{
map[][]=a[];
map[][]=a[];
map[][]=a[];
map[][]=a[];
map[][]=a[];
map[][]=a[];
map[][]=a[];
map[][]=a[];
map[][]=a[];
map[][]=a[];
ans+=f();
}while(next_permutation(a,a+));
cout<<ans<<endl;
return ;
}

方法二: dfs

#include <stdio.h>
#include <stdlib.h> int ans = , flag[] = {}; int Check(int a[][], int x, int y)
{
static int dx[] = {, -, -, -}, dy[] = {-, -, , }; for(int i = ; i < ; i ++)
if( (x + dx[i] >= && x + dx[i] < ) && (y + dy[i] >= && y + dy[i] < ) )
{
if( == abs(a[x][y] - a[ x + dx[i] ][ y + dy[i] ]))
return ;
} return ;
} void dfs(int a[][], int x, int y)
{
if( == x && == y){
ans ++;
return ;
} for(int num = ; num <= ; num ++)
if(!flag[num]){
a[x][y] = num;
flag[num] = ; if(Check(a, x, y)){
if(y + < )
dfs(a, x, y + );
else
dfs(a, x + , );
}
flag[num] = ;
}
} int main()
{
int a[][] = {-};
dfs(a, , );
printf("%d", ans);
return ;
}

方法三:

看到这题第一个想到的方法就是回溯,就很像八皇后,能填进去就填,填不进去就看下一个位置(我做的是0---9不重复使用)

我感觉这题麻烦就在判断上

1.首先要判断一个点的8个方向相减的绝对值是否为1,为1不能填入,不为1判断是否使用过这个数,没使用填入 进行下一个位置

2.如果填入的位置到达最后一列应该换行看下一行的第一个位置进行判断

3.填到最后每一个情况总sum++就行了

上代码

#include<iostream>
using namespace std;
int a[][];
int num = ;
int v[] = {};
int pd(int k, int i, int j){//这个就是判断啦。。写的有点繁琐
if (i->= && (a[i - ][j] == k - || a[i - ][j] == k + ) )
return ;
if (j->= && (a[i][j - ] == k + || a[i][j - ] == k - ) )
return ;
if (i->= && j->= && (a[i - ][j - ] == k + || a[i - ][j - ] == k - ))
return ;
if (i->= && j+< && (a[i - ][j + ] == k + || a[i - ][j + ] == k - ))
return ;
if (j + < && (a[i][j + ] == k + || a[i][j + ] == k - ))
return ;
if (i + < && (a[i + ][j] == k + || a[i + ][j] == k - ))
return ;
if (i + < && j - >= && (a[i + ][j - ] == k + || a[i + ][j - ] == k - ))
return ;
if (i + < && j + < && (a[i + ][j + ] == k + || a[i + ][j + ] == k - ))
return ;
return ;
}
void f(int i, int j){
if (i == &&j==){//已经填入到最后一个说明这种情况满足,num++
num++;
return;
}
for (int k = ; k <= ; k++){
if (pd(k, i, j)&&v[k]==) {//判断8个方向是否能填入,并且是否用过
v[k] = ;
a[i][j] = k;
if (j == )//到达最后一列记得换行
f(i + , );
else
f(i, j + );
a[i][j] = -;
v[k] = ;
}
}
}
int main(){
for (int i = ; i < ; i++)//这里我将所有数赋值-9,因为第一个和最后一个不需要赋值,避免干扰
for (int j = ; j < ; j++)
a[i][j] = -;
f(, );
printf("%d", num);
return ;
}
#include <bits/stdc++.h>
using namespace std; /*本来要判断八个格子,
*但是由于是从左往右从上往下填的,
*只要判断左、左上、上、右上
*/
const int dx[]={,-,-,-};
const int dy[]={-,-,,};
const int INF=1e9;
bool used[];
int ans=;
int a[][]; bool alright(int n,int x,int y)
{
for (int i=;i<;i++) {
int xx=x+dx[i],yy=y+dy[i];
if (xx<||yy<||xx>||yy>) continue;
if (abs(n-a[xx][yy])==) return false;
}
return true;
} void dfs(int x,int y)
{
if (x==&&y==) {
ans++;
return;
}
for (int i=;i<=;i++) {
if (!used[i]&&alright(i,x,y)) {
a[x][y]=i;
used[i]=true;
if (y==) dfs(x+,);
else dfs(x,y+);
used[i]=false;
a[x][y]=-INF;
}
}
} int main()
{
for (int i=;i<=;i++) {
for (int j=;j<=;j++) {
a[i][j]=-INF;
}
}
dfs(,);
printf("%d\n",ans);
return ;
}