蓝桥杯:方格填数 暴力解法

如图,如下的10个格子,填入0~9的数字。要求:连续的两个数字不能相邻。(左右、上下、对角都算相邻)一共有多少种可能的填数方案?请填写表示方案数目的整数。
在这里插入图片描述

思路

可以线性化这个方格,然后用【全排列函数】next_permutation,给出全排列,然后判断,但是多余情况比较多,而且线性化之后,判断变得麻烦

不如直接模拟这个方格,然后dfs+状态重置

  • 如何表示一个未填写的位置呢?用一个很大的数(inf)这样无论怎么填,0 ~ 9都不会与 inf 相邻
  • 如何避免边界判断?使用一圈 inf 填充方格

值得注意的是每一行的列数不同,需要单独判断
这样做的优点是在填的时候就剪枝了,省去不必要的情况了

代码

答案 1580

#include <iostream>
#include <cstring>
#include <cmath> 

using namespace std;

#define inf 114	// 大数保证空位不会和0~9相邻
#define iabs(x) ((int)fabs(x))

int a[6][6];
int visited[10];

int cnt = 0;

// 通过差值判断是否相邻
int can(int x, int y, int val)
{
	if(iabs(a[x-1][y]-val)>1
	&& iabs(a[x+1][y]-val)>1
	&& iabs(a[x][y-1]-val)>1
	&& iabs(a[x][y+1]-val)>1
	&& iabs(a[x-1][y-1]-val)>1
	&& iabs(a[x-1][y+1]-val)>1
	&& iabs(a[x+1][y-1]-val)>1
	&& iabs(a[x+1][y+1]-val)>1)
	{
		return 1;
	}
	else
	{
		return 0;
	}
}

// 注意对每一行单独处理
// 填第row行第column列,然后从左到右从上到下填
void dfs(int row, int column)
{
	if(row == 1)
	{
		for(int i=0; i<=9; i++)
		{
			if(visited[i] == 0 && can(row, column, i)==1)
			{
				visited[i] = 1;
				a[row][column] = i;
				if(column == 4)
				{
					dfs(row+1, 1);
				}
				else
				{
					dfs(row, column+1);
				}
				visited[i] = 0;
				a[row][column] = inf;
			}
		}
	}
	else if(row == 2)
	{
		for(int i=0; i<=9; i++)
		{
			if(visited[i] == 0 && can(row, column, i)==1)
			{
				visited[i] = 1;
				a[row][column] = i;
				if(column == 4)
				{
					dfs(row+1, 1);
				}
				else
				{
					dfs(row, column+1);
				}
				visited[i] = 0;
				a[row][column] = inf;
			}
		}
	}
	else if(row == 3)
	{
		for(int i=0; i<=9; i++)
		{
			if(visited[i] == 0 && can(row, column, i)==1)
			{
				visited[i] = 1;
				a[row][column] = i;
				if(column == 3)
				{
					dfs(row+1, 1);
				}
				else
				{
					dfs(row, column+1);
				}
				visited[i] = 0;
				a[row][column] = inf;
			}
		}
	}
	else if(row == 4)
	{
		// 填完了,计数
		cnt += 1;
	}
}

int main()
{
	memset(visited, 0, sizeof(visited));
	for(int i=0; i<6; i++)
	{
		for(int j=0; j<6; j++)
		{
			a[i][j] = inf;
		}
	}
	
	dfs(1, 2);
	
	cout<<cnt<<endl;
	
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值