10.19xiao米(已改编)-三语言题解

🍭 大家好这里是 春秋招笔试突围,一起备战大厂笔试

💻 ACM金牌团队🏅️ | 多次AK大厂笔试 | 大厂实习经历

✨ 本系列打算持续跟新 春秋招算法题

👏 感谢大家的订阅➕ 和 喜欢💗 和 手里的小花花🌸

✨ 算法合集传送们 -> 🧷学长刷题笔记

🍒 本专栏已收集 140+ 套题,算法题 会在第一时间跟新

🍄 题面描述等均已改编,如果和你笔试题看到的题面描述不一样请理解,做法和题目本质基本不变。

🍹 感谢各位朋友们的订阅,你们的支持是我们创作的最大动力 💞

alt

🧸 研发和算法岗的卷子第一题一样,最后一题不一样,研发的相对来说简单点哦

1️⃣ DFS搜索所有的状态

2️⃣ 考虑到状态的数量很少,BFS遍历所有状态

♟️ 01.LYA的魔法棋盘 评测链接🔗

问题描述

LYA是一位年轻的魔法师,她最近发明了一种奇特的魔法棋盘游戏。这个棋盘是一个 的方格,需要将数字 不重不漏地填入其中。但是,这个棋盘有一个特殊的魔法规则:任何相邻的数字(上下左右)之间的差的绝对值不能为

例如,如果在中间位置填了数字 ,那么数字 就不能出现在数字 的上下左右四个位置中的任何一个。

LYA已经在棋盘上填了一些数字,她想知道还有多少种不同的方法可以完成这个魔法棋盘。当且仅当至少有一个位置在两种填法中填充的数字不同时,这两种填法才被认为是不同的。

输入格式

第一行包含一个整数 ,表示测试用例的数量。

对于每个测试用例,有三行输入,每行包含三个整数。这 的数字矩阵代表 LYA 的魔法棋盘当前状态。如果某个位置的数字为 ,表示该位置尚未填充;如果是 之间的整数,则表示 LYA 已经在该位置填入的数字。

输出格式

对于每个测试用例,输出一行,包含一个整数,表示完成魔法棋盘的合法方案数。如果没有任何可行的方案,输出

样例

样例输入1

2
1 8 5
4 6 3
0 2 0
1 3 5
2 6 8
2 7 0

样例输出1

2
0

样例解释

样例 解释说明
样例1 对第一组数据,有两种合法填法:
1 8 5
4 6 3
7 2 9
或者
1 8 5
4 6 3
9 2 7
这两种填法都满足相邻数字差的绝对值不为1的条件。

对第二组数据,唯一的填法是:
1 3 5
4 6 8
2 7 9
但这种填法不合法,因为数字9与其上方的8相差1。因此合法方案数为0。

数据范围

  • ,其中 表示输入矩阵中第 行第 列的数字

题解

DFS

需要一个函数来检查当前填入的数字是否合法。这个函数需要检查:

  • 填入的数字是否与周围(上下左右)的数字相差1
  • 填入的数字是否已经在棋盘上出现过

DFS 来尝试填充每个空位:

  • 如果当前位置已经有数字,就移动到下一个位置
  • 如果当前位置是空的,尝试填入1到9的每个数字
  • 对于每次尝试,都检查是否合法
  • 如果合法,继续填充下一个位置
  • 如果所有位置都填满了,就找到了一个合法方案,计数加1
  1. 在搜索过程中,使用一个布尔数组来记录哪些数字已经被使用,这样可以快速检查是否有重复数字。

  2. 时间复杂度分析:最坏情况下,我们需要尝试9!种排列,即O(9!)。但实际上,由于题目的限制条件,大多数情况下搜索树会被很快剪枝,实际运行时间会比理论上的最坏情况好得多。

  3. 空间复杂度:只需要O(1)的额外空间来存储棋盘和已使用数字的标记。

参考代码

  • Python
# 读取测试用例数量
T = int(input())

# 定义方向数组,用于检查相邻位置
directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]

def is_valid(board, x, y, num):
    """
    检查在位置(x, y)放置数字num是否合法
    """
    # 检查相邻位置
    for dx, dy in directions:
        nx, ny = x + dx, y + dy
        if 0 <= nx < 3 and 0 <= ny < 3:
            if board[nx][ny] != 0 and abs(board[nx][ny] - num) == 1:
                return False
    return True

def dfs(board, x, y, used):
    """
    深度优先搜索填充棋盘
    """
    # 如果已经填充完所有位置,找到一个解
    if x == 3:
        return 1
    
    # 移动到下一个位置
    next_x, next_y = (x, y + 1) if y < 2 else (x + 1, 0)
    
    # 如果当前位置已经有数字,直接处理下一个位置
    if board[x][y] != 0:
        return dfs(board, next_x, next_y, used)
    
    count = 0
    # 尝试填充1-9的数字
    for num in range(1, 10):
        if not used[num] and is_valid(board, x, y, num):
            board[x][y] = num
            used[num] = True
            count += dfs(board, next_x, next_y, used)
            board[x][y] = 0
            used[num] = False
    
    return count

# 处理每个测试用例
for _ in range(T):
    board = [list(map(int, input().split())) for _ in range(3)]
    used = [False] * 10
    
    # 标记已使用的数字
    for row in board:
        for num in row:
            if num != 0:
                used[num] = True
    
    # 计算合法方案数
    result = dfs(board, 0, 0, used)
    print(result)
  • Java
import java.util.*;

public class Main {
    // 定义方向数组,用于检查相邻位置
    static int[][] directions = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
    
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int T = scanner.nextInt();
        
        for (int t = 0; t < T; t++) {
            int[][] board = new int[3][3];
            boolean[] used = new boolean[10];
            
            // 读取棋盘状态
            for (int i = 0; i < 3; i++) {
                for (int j = 0; j < 3; j++) {
                    board[i][j] = scanner.nextInt();
                    if (board[i][j] != 0) {
                        used[board[i][j]] = true;
                    }
                }
            }
            
            // 计算并输出结果
            System.out.println(dfs(board, 0, 0, used));
        }
    }
    
    // 检查在位置(x, y)放置数字num是否合法
    static boolean isValid(int[][] board, int x, int y, int num) {
        for (int[] dir : directions) {
            int nx = x + dir[0], ny = y + dir[1];
            if (nx >= 0 && nx < 3 && ny >= 0 && ny < 3) {
                if (board[nx][ny] != 0 && Math.abs(board[nx][ny] - num) == 1) {
                    return false;
                }
            }
        }
        return true;
    }
    
    // 深度优先搜索填充棋盘
    static int dfs(int[][] board, int x, int y, boolean[] used) {
        if (x == 3) {
            return 1;
        }
        
        int nextX = y == 2 ? x + 1 : x;
        int nextY = y == 2 ? 0 : y + 1;
        
        if (board[x][y] != 0) {
            return dfs(board, nextX, nextY, used);
        }
        
        int count 

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

学长刷题笔记 文章被收录于专栏

这里收集了超全的刷题笔记,欢迎大家的订阅,会持续跟新的

全部评论

相关推荐

1.自我介绍2.const的用法有哪些说了声明全局变量和常成员函数3.static的用法有哪些说了声明静态全局变量和单例模式4.说一说面向对象思想照着面经上写的答的5.动态多态的实现方式答了虚函数和虚函数表6.重载和重写的区别照着面经上写的答的7.说一说智能指针答了auto_ptr,scoped_ptr,unique_ptr和shared_ptr,weak_ptr,从auto_ptr过渡到unique_ptr解决隐式资源转移问题,shared_ptr的底层实现,还说了shared_ptr的循环引用计数问题。8.shared_ptr是线程安全的吗我答了不是,实际上是的9.线程和进程的区别答了Linux的进程到线程的发展历史,然后再说的区别10.线程的同步和进程的通信,写一段伪代码模拟一下死锁场景答了各种方式,他没有挑具体哪种方式的原理。11.Lambda表达式的捕捉列表使用答了=和&amp;的区别12.常用的STL容器有哪些,各自的使用场景顺序容器,容器适配器,关联容器全说了一遍,还把底层数据结构和操作说了一遍,说的我都喘气了。13.项目一的业务功能简单介绍了一下功能,他没有深入去问14.Qt的槽和信号的原理我说和Linux的信号和信号捕捉函数很类似15.槽和信号的使用步骤答了emit和connect16.Qt是如何实现波浪式按钮的,Qt是如何实现悬停移动式卡片的答了用QGraphicsOpacityEffect实现了透明效果,QPropertyAnimation实现了平滑移动效果17.写伪代码实现单例模式,如果要保证线程安全怎么改进,如果这个单例类要作为基类,并且子类继承这个基类也可以变成单例类,要怎么实现就写出了线程安全版本的,他说要达到第三点效果需要使用到模板18.说一下快排和归并排序的思路说会通知二面
点赞 评论 收藏
分享
3 2 评论
分享
牛客网
牛客企业服务