java 洛谷题单【算法1-7】搜索

news2024/11/24 6:45:04

P1219 [USACO1.5] 八皇后 Checker Challenge

解题思路

回溯法

递归与回溯:

  • 从第0行开始,为每个行尝试放置棋子的位置,检查放置是否违反约束条件。
  • 如果放置合法,则继续递归处理下一行(即下一层递归)。
  • 如果当前行无法找到合法位置,说明之前的摆放有误,需回溯到上一层,重新选择其他位置。

当n=13时代码会超时,这里打表解决。本题也可以直接全部打表。

import java.util.ArrayList;
import java.util.Scanner;

public class Main {
    static int ans = 0;
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        if (n == 13) {
            System.out.println("1 3 5 2 9 12 10 13 4 6 8 11 7 ");
            System.out.println("1 3 5 7 9 11 13 2 4 6 8 10 12 ");
            System.out.println("1 3 5 7 12 10 13 6 4 2 8 11 9 ");
            System.out.println("73712");
            return;
        }
        solveNQueens(n);
        System.out.println(ans);
    }

    public static void solveNQueens(int n) {
        // 如果n小于等于0,直接返回
        if (n <= 0) {
            return;
        }
        // 调用solve方法,解n皇后问题
        solve(n, new ArrayList<>(), new ArrayList<>());
    }

    private static void solve(int n, ArrayList<Integer> row, ArrayList<Integer> col) {
        // 如果行的长度等于n,则打印结果
        if (row.size() == n) {
            print(row);
            return;
        }
        // 遍历每一列
        for (int i = 0; i < n; i++) {
            // 如果这一列没有被使用过,且这一行满足条件
            if (!col.contains(i) && isValid(row, i)) {
                // 将这一列添加到行中
                row.add(i);
                // 将这一列添加到列中
                col.add(i);
                // 递归调用
                solve(n, row, col);
                // 回溯
                row.remove(row.size() - 1);
                col.remove(col.size() - 1);
            }
        }
    }

    // 判断当前位置是否可以放置皇后
    private static boolean isValid(ArrayList<Integer> row, int col) {
        // 遍历已经放置皇后的列
        for (int i = 0; i < row.size(); i++) {
            // 判断当前位置的列和已经放置皇后的列是否相等,或者当前位置的列和已经放置皇后的列的绝对值是否等于当前位置的行和已经放置皇后的行的差值
            if (row.get(i) == col || Math.abs(row.get(i) - col) == row.size() - i) {
                return false;
            }
        }
        return true;
    }

    private static void print(ArrayList<Integer> row) {
        int n = row.size();
        // 输出前3种答案
        if (ans < 3){
            for (Integer integer : row) {
                for (int j = 0; j < n; j++) {
                    if (integer == j) {
                        j++;
                        System.out.print(j + " ");
                    }
                }
            }
            System.out.println();
        }
        ans++;
    }
}

DFS

一步到位

import java.util.Scanner;

public class Main {
    static final int N = 14; // 最大棋盘大小,比13大就行
    static boolean[] col = new boolean[N]; // 记录列是否被占用
    static boolean[] dia1 = new boolean[2 * N]; // 记录主对角线是否被占用
    static boolean[] dia2 = new boolean[2 * N]; // 记录副对角线是否被占用
    static int[] pos = new int[N]; // 存放当前棋子的放置位置
    static int n, ans = 0; // n 为棋盘大小,ans 为找到的解的数量

    static void dfs(int u) {
        if (u > n) { // 如果棋子放置完毕
            if (ans < 3) { // 如果找到的解少于 3 个
                for (int i = 1; i <= n; i++) {
                    System.out.print(pos[i] + " ");
                }
                System.out.println();
            }
            ans++; // 解的数量加 1
            return;
        }
        for (int i = 1; i <= n; i++) {
            // 检查当前位置是否合法
            if (col[i] || dia1[u - i + n] || dia2[i + u]) continue;
            col[i] = true; // 标记列为已被占用
            dia1[u - i + n] = true; // 标记主对角线为已被占用
            dia2[i + u] = true; // 标记副对角线为已被占用
            pos[u] = i; // 放置棋子
            dfs(u + 1); // 尝试放置下一个棋子
            // 回溯
            col[i] = false; // 取消标记列为未被占用
            dia1[u - i + n] = false; // 取消标记主对角线为未被占用
            dia2[i + u] = false; // 取消标记副对角线为未被占用
            pos[u] = 0; // 清空当前位置
        }
    }

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        n = input.nextInt();
        // 从第一行开始放置棋子
        dfs(1);
        System.out.println(ans);
    }
}

P2392 kkksc03考前临时抱佛脚

解题思路

动态规划

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);

        // 读取每个科目题目的数量
        int[] a = new int[5];
        for (int i = 1; i <= 4; i++) {
            a[i] = input.nextInt();
        }

        // 定义用于存储题目时间的数组和动态规划数组
        int[] homework = new int[21];
        int[] dp = new int[2501];

        int totalMinTime = 0;

        // 对每个科目进行处理
        for (int i = 1; i <= 4; i++) {
            int sum = 0;

            // 读取每个科目的题目时间
            for (int j = 1; j <= a[i]; j++) {
                homework[j] = input.nextInt();
                sum += homework[j];
            }

            // 0/1背包算法,计算达到 sum/2 最大时间
            for (int j = 1; j <= a[i]; j++) {
                for (int k = sum / 2; k >= homework[j]; k--) {
                    dp[k] = Math.max(dp[k], dp[k - homework[j]] + homework[j]);
                }
            }

            // 累加每个科目达到的最小复习时间
            totalMinTime += sum - dp[sum / 2];

            // 重置动态规划数组
            for (int j = 1; j <= sum / 2; j++) {
                dp[j] = 0;
            }
        }

        // 输出总最小复习时间
        System.out.println(totalMinTime);

    }
}

 搜索

本质上是暴力枚举,遍历每一道题求出左右脑两边时间较大值的最小值,最终返回ans。

import java.util.Scanner;

public class Main {
    // 左脑用时,右脑用时, 最小用时,答案
    static int Left, Right, min, ans;
    // 存储问题个数
    static int[] s = new int[5];
    // 存储问题和解决时间
    static int[][] arr = new int[21][5];

    // x表示当前问题,y表示当前习题集
    public static void search(int x, int y) {
        // 如果所有问题都做完了,更新最小用时
        if (x > s[y]) {
            min = Math.min(min, Math.max(Left, Right));
            return;
        }
        // 交给左脑做,递归执行,如果符合if判断,得到min值,再回溯,交给右脑做
        // 找到左右脑两边时间较大值的最小值
        Left += arr[x][y];
        search(x + 1, y);
        Left -= arr[x][y];

        Right += arr[x][y];
        search(x + 1, y);
        Right -= arr[x][y];
    }

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);

        for (int i = 0; i < 4; i++) {
            s[i] = input.nextInt();
        }

        // 遍历四个习题集
        for (int i = 0; i < 4; i++) {
            Left = Right = 0;
            min = Integer.MAX_VALUE;

            // 读入所需时间
            for (int j = 0; j < s[i]; j++) {
                arr[j][i] = input.nextInt();
            }
            // 开始搜索,从第一个习题集开始,枚举每道题分别给左右脑做,找到最小用时
            search(0, i);
            ans += min;
        }

        System.out.println(ans);
    }
}

P1443 马的遍历

解题思路

  • 初始化:

    • 创建一个二维数组 dist,用来记录从起始位置 (x, y) 到每个棋盘位置的最少步数。初始化所有位置为 -1(表示不可到达),然后将起始位置的步数设置为 0
    • 使用一个队列(Queue)来进行 BFS。将起始位置 (x, y) 放入队列中。
  • BFS 过程:

    • 从队列中取出当前的位置 (currentX, currentY) 进行处理。
    • 对骑士的 8 种可能的移动方式,计算新的位置 (newX, newY)
    • 检查新的位置是否在棋盘的范围内,以及是否尚未访问(dist[newX][newY] == -1)。
    • 如果满足条件,则更新 dist 数组中新的位置的步数,并将其加入队列中以备进一步处理。
  • 输出结果:

    • 最后,输出棋盘上每个位置的最小步数,如果位置不可达,输出 -1
import java.util.*;

public class Main {
    // BFS
    public static void minSteps(int n, int m, int x, int y) {
        // 将起始位置转换为基于0的索引
        x -= 1;
        y -= 1;

        // 象棋中马在棋盘上可能的走法
        int[][] Moves = {
                {-2, -1}, {-2, 1}, {-1, -2}, {-1, 2},
                {1, -2}, {1, 2}, {2, -1}, {2, 1}
        };

        // 初始化距离矩阵-1(不可达),并将起始位置的距离设为0
        int[][] dist = new int[n][m];
        for (int[] row : dist) {
            Arrays.fill(row, -1);
        }
        dist[x][y] = 0;

        //BFS队列初始化
        Queue<int[]> queue = new LinkedList<>();
        queue.offer(new int[]{x, y});

        // 开始搜索
        while (!queue.isEmpty()) {
            int[] current = queue.poll();
            int currentX = current[0];
            int currentY = current[1];
            int currentDist = dist[currentX][currentY];

            for (int[] move : Moves) {
                int newX = currentX + move[0];
                int newY = currentY + move[1];

                //检查新位置是否在限定范围内并且尚未访问过
                if (newX >= 0 && newX < n && newY >= 0 && newY < m && dist[newX][newY] == -1) {
                    dist[newX][newY] = currentDist + 1;
                    queue.offer(new int[]{newX, newY});
                }
            }
        }

        // 输出结果
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                System.out.print(dist[i][j] + " ");
            }
            System.out.println();
        }
    }

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);

        int n = input.nextInt();
        int m = input.nextInt();
        int x = input.nextInt();
        int y = input.nextInt();

        minSteps(n, m, x, y);
    }
}

P1135 奇怪的电梯

解题思路

这是一道最短路问题,可以理解为每次建两条边,i(1\leq i \leq n)\rightarrow i-K_i(1\leq i - K_i),i+K_i(i+K_i\leq n)

DFS深度优先搜索 

import java.util.Arrays;
import java.util.Scanner;

public class Main {
    static int n, a, b;
    static int[] k = new int[201];
    // 用于存储从起点到图中所有其他节点的最短距离
    static int[] dis = new int[201];

    static void dfs(int node, int step) {
        dis[node] = step; // 更新距离

        // 当前层数减去对应的k值,如果大于1并且步数小于当前记录的步数,则继续向下搜索
        int v = node - k[node];
        if (1 <= v && step + 1 < dis[v]) {
            dfs(v, step + 1);
        }

        // 当前层数加上对应的k值,如果小于等于n并且步数小于当前记录的步数,则继续向上搜索
        v = node + k[node];
        if (v <= n && step + 1 < dis[v]) {
            dfs(v, step + 1);
        }
    }

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        // 初始化距离数组
        Arrays.fill(dis, Integer.MAX_VALUE);

        n = input.nextInt();
        a = input.nextInt();
        b = input.nextInt();

        for (int i = 1; i <= n; i++) {
            k[i] = input.nextInt();
        }

        // 从a层开始,目前步数为0
        dfs(a, 0);
        // 判断是否能到达b层,不能输出-1,能则输出步数
        System.out.println(dis[b] == Integer.MAX_VALUE ? -1 : dis[b]);
    }
}

P2895 [USACO08FEB] Meteor Shower S

解题思路

  • 定义问题: 贝茜从起点 (0, 0) 出发,目标是找到一个不会被流星影响的安全格子。由于流星坠落会把坠落点及其四周的格子烧焦,我们需要计算出每个格子变为不可走的最早时间。

  • 流星影响范围: 对于每颗流星坠落的位置 (X_i, Y_i),该流星会将它的周围四个相邻的格子(上下左右四个方向)也烧焦。因此,每颗流星会影响五个格子:(X_i, Y_i) 及其上下左右。

  • 最早烧焦时间表: 我们需要一个数组 minBurnTime[x][y] 来记录每个格子最早被烧焦的时刻。初始时,这些值为无穷大(即未被烧焦)。然后,遍历每颗流星,更新流星及其影响的格子的烧焦时间。

  • 广度优先搜索 (BFS): 在时刻 t = 0,贝茜从 (0, 0) 开始,通过 BFS 在四个方向上搜索下一个可以走的格子。我们需要确保贝茜只走在还未被流星烧焦的格子上,并且格子在贝茜抵达的时刻之前没有被烧焦。

  • 终止条件: 如果贝茜找到一个永远不会被烧焦的格子,那么返回到达这个格子的最短时间。如果所有可以走的格子最终都被烧焦了,则返回 -1 表示不可能到达安全区域。

import java.util.*;

public class Main {
    // 定义方向向量:上,下,左,右
    private static final int[] dx = {-1, 1, 0, 0};
    private static final int[] dy = {0, 0, -1, 1};
    private static final int MAX_COORD = 305;  // 坐标最大值范围 [0, 300]
    private static final int INF = Integer.MAX_VALUE;

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int M = input.nextInt();

        // 初始化每个格子的最早烧焦时间
        int[][] minBurnTime = new int[MAX_COORD][MAX_COORD];
        for (int i = 0; i < MAX_COORD; i++) {
            Arrays.fill(minBurnTime[i], INF);
        }

        // 读取流星信息,并更新烧焦时间
        for (int i = 0; i < M; i++) {
            int X = input.nextInt();
            int Y = input.nextInt();
            int T = input.nextInt();
            updateBurnTime(minBurnTime, X, Y, T);
        }

        // 用BFS进行最短路径搜索
        int result = bfs(minBurnTime);
        System.out.println(result);
    }

    // 更新流星影响的格子及其周围格子的烧焦时间
    private static void updateBurnTime(int[][] minBurnTime, int x, int y, int t) {
        for (int i = 0; i < 4; i++) {
            int nx = x + dx[i];
            int ny = y + dy[i];
            if (isInBounds(nx, ny)) {
                minBurnTime[nx][ny] = Math.min(minBurnTime[nx][ny], t);
            }
        }
        minBurnTime[x][y] = Math.min(minBurnTime[x][y], t);  // 流星落地点也要更新
    }

    // 广度优先搜索 (BFS) 寻找最短路径
    private static int bfs(int[][] minBurnTime) {
        Queue<int[]> queue = new LinkedList<>();
        boolean[][] visited = new boolean[MAX_COORD][MAX_COORD];
        queue.offer(new int[]{0, 0, 0});  // {x, y, time}
        visited[0][0] = true;

        while (!queue.isEmpty()) {
            int[] current = queue.poll();
            int x = current[0];
            int y = current[1];
            int time = current[2];

            // 如果当前位置的烧焦时间大于当前时间,说明贝茜可以安全站在这里
            if (minBurnTime[x][y] == INF) {
                return time;  // 找到一个永远不会烧焦的格子
            }

            // 遍历四个方向
            for (int i = 0; i < 4; i++) {
                int nx = x + dx[i];
                int ny = y + dy[i];
                int nextTime = time + 1;

                if (isInBounds(nx, ny) && !visited[nx][ny] && nextTime < minBurnTime[nx][ny]) {
                    queue.offer(new int[]{nx, ny, nextTime});
                    visited[nx][ny] = true;
                }
            }
        }

        return -1;  // 无法到达安全地点
    }

    // 判断是否在有效范围内
    private static boolean isInBounds(int x, int y) {
        return x >= 0 && x < MAX_COORD && y >= 0 && y < MAX_COORD;
    }
}

P1036 [NOIP2002 普及组] 选数

解题思路

  • 组合生成:使用了回溯算法(backtracking)来生成所有可能的组合。generateCombinations 函数递归地构建每一个组合,遇到有效组合时将其加入结果列表。
  • 素数判断isPrime 函数通过检查一个数是否可以被其小于等于平方根的数整除,来判断其是否为素数。
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in); 
        int n = input.nextInt(); // 输入数组长度 n
        int k = input.nextInt(); // 输入要选择的元素个数 k
        int[] numbers = new int[n]; // 创建长度为 n 的数组用于存放输入的数字
        for (int i = 0; i < n; i++) {
            numbers[i] = input.nextInt(); 
        }

        List<List<Integer>> combinations = new ArrayList<>(); // 用于存放所有 k 个元素的组合
        // 生成所有长度为 k 的组合
        generateCombinations(numbers, n, k, 0, new ArrayList<>(), combinations);

        int primeCount = 0; // 用于计数素数和的组合个数
        
        // 遍历所有组合,计算每个组合的元素和,并判断是否为素数
        for (List<Integer> combination : combinations) {
            int sum = combination.stream().mapToInt(Integer::intValue).sum(); // 计算组合元素的和
            if (isPrime(sum)) { // 如果和是素数
                primeCount++; // 素数组合个数加 1
            }
        }

        System.out.println(primeCount);
    }

    // 递归生成数组中长度为 k 的所有组合
    private static void generateCombinations(int[] arr, int n, int k, int index, List<Integer> current, List<List<Integer>> combinations) {
        // 如果当前组合的大小等于 k,说明生成了一个合法的组合,加入组合列表
        if (current.size() == k) {
            combinations.add(new ArrayList<>(current)); // 保存当前组合
            return; // 返回不再继续递归
        }
        // 如果遍历完了数组,则返回
        if (index == n) {
            return;
        }
        // 选择当前索引的元素,并继续递归生成剩下的组合
        current.add(arr[index]);
        generateCombinations(arr, n, k, index + 1, current, combinations);
        // 不选择当前索引的元素,尝试其他组合
        current.remove(current.size() - 1);
        generateCombinations(arr, n, k, index + 1, current, combinations);
    }

    // 判断一个数是否为素数
    private static boolean isPrime(int num) {
        if (num <= 1) {
            return false; // 小于或等于 1 的数不是素数
        }
        // 通过检查从 2 到 sqrt(num) 的所有数,判断是否存在能整除 num 的数
        for (int i = 2; i <= Math.sqrt(num); i++) {
            if (num % i == 0) { // 如果存在整除因子,说明 num 不是素数
                return false;
            }
        }
        return true; // 没有发现整除因子,num 是素数
    }
}

P2036 [COCI2008-2009 #2] PERKET 

解题思路

  • 穷举所有可能的配料组合

    • 这里采用了位运算的技巧来枚举所有可能的食材组合。对于每个食材,可以选择是否加入组合中,因此总共有 2n−12^n - 12n−1 种组合(从 1 到 2n−12^n - 12n−1 表示选择的子集)。
    • i 作为枚举的组合编号,表示当前选择了哪些食材。1 << n 表示有 2n2^n2n 种组合可能(即每个食材可以选择或不选择),从 1 开始,因为编号为 0 的子集是空集。
  • 计算酸味和苦味的总值

    • 对于每一个组合 i,内部循环使用 if ((i & (1 << j)) != 0) 来判断当前组合是否包含第 j 个食材。通过位运算,可以检测到当前组合 i 中是否包含第 j 个食材。
    • 如果包含,就将第 j 个食材的酸味乘入总酸味 totalS,并将苦味加到总苦味 totalB
  • 计算差值并更新最小差值

    • 对于每个组合,计算总酸味与总苦味之间的绝对差值 currentDifference,并将其与当前最小差值 minDifference 比较。如果当前差值更小,则更新 minDifference
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);

        int n = input.nextInt();
        int[] s = new int[n];
        int[] b = new int[n];

        for (int i = 0; i < n; i++) {
            s[i] = input.nextInt();
            b[i] = input.nextInt();
        }

        int minDifference = Integer.MAX_VALUE;

        // 枚举所有可能的配料组合(子集)
        for (int i = 1; i < (1 << n); i++) {
            int totalS = 1;
            int totalB = 0;

            for (int j = 0; j < n; j++) {
                if ((i & (1 << j)) != 0) {
                    totalS *= s[j];
                    totalB += b[j];
                }
            }

            int currentDifference = Math.abs(totalS - totalB);
            if (currentDifference < minDifference) {
                minDifference = currentDifference;
            }
        }

        System.out.println(minDifference);
    }
}

 P1433 吃奶酪

解题思路

这个问题可以归结为经典的旅行商问题(TSP, Traveling Salesman Problem)。由于小老鼠需要从原点 (0,0) 出发,访问所有的奶酪并返回终点,因此可以使用递归或动态规划的方法来求解最短路径。

  • 求距离:根据两点距离公式 $\sqrt{(x_1-x_2)^2 + (y_1-y_2)^2}$ 来计算老鼠从一个点移动到另一个点的距离。
  • 递归解决TSP问题:老鼠从原点出发,访问所有奶酪块,然后返回原点。我们可以利用状态压缩动态规划来解决问题,枚举每一个奶酪块作为起点,通过递归计算走遍所有块的最短路径。
  • 状态压缩DP:利用一个位掩码来记录已经访问过的奶酪点的状态。
import java.util.Arrays;
import java.util.Scanner;

public class Main {

    static double[][] dist = new double[20][20]; // 距离矩阵,从第i块奶酪到第j块的距离
    static double[] x = new double[20], y = new double[20]; // 奶酪的坐标
    static double[][] dp = new double[18][1 << 18]; // 状态压缩DP数组
    static int n; // 奶酪数量

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        n = input.nextInt();

        // 读取每块奶酪的坐标
        for (int i = 1; i <= n; i++) {
            x[i] = input.nextDouble();
            y[i] = input.nextDouble();
        }

        // 原点 (0, 0)
        x[0] = 0;
        y[0] = 0;

        // 初始化距离矩阵
        for (int i = 0; i <= n; i++) {
            for (int j = i + 1; j <= n; j++) {
                dist[i][j] = distance(i, j);
                dist[j][i] = dist[i][j]; // 对称性
            }
        }

        // 初始化dp数组,设置为无穷大
        for (int i = 0; i < 18; i++) {
            Arrays.fill(dp[i], Double.MAX_VALUE);
        }

        // 初始化: 在i点上,且只经过i点时的最短距离为从原点到i点的距离
        for (int i = 1; i <= n; i++) {
            dp[i][1 << (i - 1)] = dist[0][i];
        }

        // 枚举所有状态
        for (int mask = 1; mask < (1 << n); mask++) {
            for (int i = 1; i <= n; i++) {
                // 如果i点没在当前的状态mask中,跳过
                if ((mask & (1 << (i - 1))) == 0) continue;

                // 遍历所有可能的点j,寻找最小值
                for (int j = 1; j <= n; j++) {
                    if (i == j || (mask & (1 << (j - 1))) == 0) continue;

                    // 更新dp[i][mask],选择从j到i的最短路径
                    dp[i][mask] = Math.min(dp[i][mask], dp[j][mask ^ (1 << (i - 1))] + dist[i][j]);
                }
            }
        }

        // 找到走完所有点的最短路径
        double ans = Double.MAX_VALUE;
        int finalMask = (1 << n) - 1; // 所有点都经过的状态
        for (int i = 1; i <= n; i++) {
            ans = Math.min(ans, dp[i][finalMask]);
        }

        // 输出答案,保留两位小数
        System.out.printf("%.2f\n", ans);
    }

    // 计算第v个和第w个奶酪之间的欧几里得距离
    private static double distance(int v, int w) {
        return Math.sqrt((x[v] - x[w]) * (x[v] - x[w]) + (y[v] - y[w]) * (y[v] - y[w]));
    }
}

P1605 迷宫

解题思路

  • 使用深度优先搜索(DFS)枚举所有可能的路径。
  • 对每一个位置,可以尝试向上、下、左、右四个方向移动。
  • 每次移动后需要检查该位置是否为障碍物或已经访问过。
  • 如果到达终点则记录方案数。
  • 递归回溯过程中注意恢复状态以便探索其他可能路径。
import java.util.Scanner;

public class Main {
    // 迷宫的大小和障碍物位置
    static int N, M, T;
    static int[][] maze;

    // 起点和终点坐标
    static int startX, startY, endX, endY;

    // 四个方向数组,用于表示上下左右移动
    static int[] dx = {0, 1, 0, -1}; // 右、下、左、上
    static int[] dy = {1, 0, -1, 0}; // 右、下、左、上

    // 用于记录方案数
    static int count = 0;

    // 主函数
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);

        // 读取迷宫的尺寸和障碍物数目
        N = input.nextInt();
        M = input.nextInt();
        T = input.nextInt();

        // 初始化迷宫,0 表示可通行,-1 表示障碍物
        maze = new int[N + 1][M + 1];

        // 读取起点和终点坐标
        startX = input.nextInt();
        startY = input.nextInt();
        endX = input.nextInt();
        endY = input.nextInt();

        // 读取障碍物位置
        for (int i = 0; i < T; i++) {
            int obsX = input.nextInt();
            int obsY = input.nextInt();
            maze[obsX][obsY] = -1; // 标记障碍物
        }

        // 从起点开始深度优先搜索
        dfs(startX, startY);

        // 输出结果,即方案的数量
        System.out.println(count);
    }

    // 深度优先搜索函数
    public static void dfs(int x, int y) {
        // 如果到达终点,方案数加1
        if (x == endX && y == endY) {
            count++;
            return;
        }

        // 将当前点标记为已访问
        maze[x][y] = 1;

        // 尝试向四个方向移动
        for (int i = 0; i < 4; i++) {
            int newX = x + dx[i];
            int newY = y + dy[i];

            // 检查新位置是否在迷宫范围内,并且是可通行的
            if (newX >= 1 && newX <= N && newY >= 1 && newY <= M && maze[newX][newY] == 0) {
                dfs(newX, newY); // 递归进入新位置
            }
        }

        // 回溯:恢复当前点为未访问状态,以便探索其他路径
        maze[x][y] = 0;
    }
}

P1019 [NOIP2000 提高组] 单词接龙

解题思路

本题建议参考题解区。本文给出的题解仅供参考。

1. 最小重叠部分计算

  • 首先,定义一个 minOverlap 函数,用于计算两个单词之间的最小重叠部分。具体方法是遍历前一个单词的后缀,寻找是否与下一个单词的前缀有重叠。
  • 预处理所有单词对之间的重叠关系,并存储在二维数组 minO[][] 中,表示两个单词之间的最小重叠长度。

2. 深度优先搜索(DFS)

  • 使用深度优先搜索 dfs 进行递归,尝试从以指定字母开头的单词出发,逐个单词接龙。
  • 在递归过程中,检查每个单词是否符合连接条件:
    • 单词最多使用两次。
    • 两个单词之间必须有重叠部分。
    • 相邻的两个单词不能存在包含关系。
  • 递归过程中,更新当前的接龙长度,并通过回溯的方式还原状态,寻找可能的更长单词链。

3. 回溯和状态更新

  • 每次尝试一个单词连接后,通过回溯的方式撤销选择,以便尝试其他可能的组合。
  • 使用 fre[] 数组记录每个单词的使用次数,确保每个单词最多使用两次。
import java.util.Scanner;

public class Main {

    static int n;                   // 单词数
    static String[] str;             // 存储字符串
    static int[][] minO;              // 两个单词的最小重叠部分
    static int[] fre;               // 判断单词使用频率
    static int ans = -1;            // 答案
    static int maxL = 0;              // 当前最长串的长度

    // mt函数,返回x单词后连接一个y单词的最小重叠部分
    public static int minOverlap(int x, int y) {
        boolean flag = true;
        // y单词从尾部向前看看最小重叠部分从哪里开始
        int ky = 0;
        int lenX = str[x].length();  // 从y单词的尾部向前看看最小重叠部分从哪里开始

        // 从x单词的尾部向前看看最小重叠部分从哪里开始
        for (int k = lenX - 1; k >= 0; k--) {
            for (int kx = k; kx < lenX; kx++) {
                // 如果两个单词的字符不相等,则说明不是最小重叠部分
                if (str[x].charAt(kx) != str[y].charAt(ky++)) {
                    flag = false;
                    break;
                }
            }
            // 如果找到最小重叠部分,则返回重叠部分的长度
            if (flag) {
                return lenX - k;
            }
            ky = 0;
            flag = true;
        }
        return 0;
    }

    // dfs函数,p为尾部单词编号
    public static void dfs(int p) {
        boolean flag = false;  // 标记是否能继续连接
        for (int i = 0; i < n; i++) {
            if (fre[i] >= 2) continue;               // 单词使用超过两次
            if (minO[p][i] == 0) continue;             // 两个单词没有重合部分
            if (minO[p][i] == str[p].length() || minO[p][i] == str[i].length()) continue;  // 存在包含关系
            maxL += str[i].length() - minO[p][i];         // 更新当前长度
            fre[i]++;                                // 该单词使用一次
            flag = true;                               // 标记成功匹配
            dfs(i);                                  // 递归继续搜索
            maxL -= str[i].length() - minO[p][i];         // 回溯时减去这部分长度
            fre[i]--;                                // 回溯时还原使用状态
        }
        if (!flag) {  // 如果不能再继续接龙,更新最大值
            ans = Math.max(ans, maxL);
        }
    }

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);

        // 输入单词数
        n = input.nextInt();
        str = new String[n];
        minO = new int[n][n];
        fre = new int[n];

        // 输入单词列表
        for (int i = 0; i < n; i++) {
            str[i] = input.next();
        }

        // 输入开头的字母
        char ch = input.next().charAt(0);

        // 预处理,计算两个单词的最小重叠部分
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                minO[i][j] = minOverlap(i, j);
            }
        }

        // 从每个以开头字母为起点的单词开始搜索
        for (int i = 0; i < n; i++) {
            if (str[i].charAt(0) == ch) {
                fre[i]++;              // 标记该单词使用过
                maxL = str[i].length();   // 更新当前串长度
                dfs(i);                // 开始搜索
                fre[i] = 0;            // 回溯时还原状态
            }
        }

        // 输出结果
        System.out.println(ans);
    }
}

P1101 单词方阵

解题思路

  • 方向定义:在矩阵中寻找单词时,有 8 个方向需要考虑:上下、左右、四个对角线方向。
  • 查找匹配:从每个起始点出发,检查是否可以沿着某个方向找到完整的单词 yizhong
  • 标记匹配:使用一个辅助矩阵来标记哪些字母属于找到的单词,然后根据该标记矩阵输出最终结果。
import java.util.Scanner;

public class Main {
    // 定义8个方向,分别是: 上、下、左、右、左上、右上、左下、右下
    static int[] dx = {-1, 1, 0, 0, -1, -1, 1, 1};
    static int[] dy = {0, 0, -1, 1, -1, 1, -1, 1};
    static String word = "yizhong";  // 要查找的单词
    static int n;
    static char[][] matrix; // 输入矩阵
    static boolean[][] marked;  // 标记矩阵,用于记录找到的单词的位置

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        n = input.nextInt();
        matrix = new char[n][n];
        marked = new boolean[n][n];

        // 读取输入矩阵
        for (int i = 0; i < n; i++) {
            matrix[i] = input.next().toCharArray();
        }

        // 遍历矩阵的每一个位置
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                // 尝试从 (i, j) 位置出发寻找单词
                for (int d = 0; d < 8; d++) {
                    if (searchWord(i, j, d)) {
                        // 如果找到单词,标记其位置
                        markWord(i, j, d);
                    }
                }
            }
        }

        // 输出结果
        printResult();
    }

    // 在方向d上查找从 (x, y) 出发的单词是否为 "yizhong"
    public static boolean searchWord(int x, int y, int d) {
        for (int k = 0; k < word.length(); k++) {
            int nx = x + k * dx[d];
            int ny = y + k * dy[d];
            if (nx < 0 || nx >= n || ny < 0 || ny >= n || matrix[nx][ny] != word.charAt(k)) {
                return false;
            }
        }
        return true;
    }

    // 标记从 (x, y) 出发,方向d上的单词 "yizhong"
    public static void markWord(int x, int y, int d) {
        for (int k = 0; k < word.length(); k++) {
            int nx = x + k * dx[d];
            int ny = y + k * dy[d];
            marked[nx][ny] = true;  // 标记该位置为单词的一部分
        }
    }

    // 输出最终结果,将未标记的字母替换为 '*'
    public static void printResult() {
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (marked[i][j]) {
                    System.out.print(matrix[i][j]);
                } else {
                    System.out.print('*');
                }
            }
            System.out.println();
        }
    }
}

P2404 自然数的拆分问题

解题思路

  • 递归与回溯

    • 我们从最小的数(即 1)开始,不断尝试将剩余的数拆分为更小的数。
    • 使用递归函数来枚举所有可能的拆分方式。
    • 在递归过程中,需要保证当前选择的数字比上一个选择的数字要大或者相等,以保证输出序列是递增的。
  • 剪枝

    • 如果当前的和已经超过了 n,则可以提前终止当前递归分支。
    • 当剩下的数字为 0 时,表示找到了一种可行的拆分方式,将其保存。
  • 字典序输出

    • 因为我们在每次递归时都是从最小的数开始递归,因此自然满足字典序的要求。
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class Main {
    // 用于存储最终结果
    static List<List<Integer>> result = new ArrayList<>();

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        input.close();

        // 调用递归方法求解
        findCombinations(n, new ArrayList<>(), 1);

        // 按要求格式输出
        for (List<Integer> combination : result) {
            for (int i = 0; i < combination.size(); i++) {
                if (i == combination.size() - 1) {
                    System.out.print(combination.get(i));
                } else {
                    System.out.print(combination.get(i) + "+");
                }
            }
            System.out.println();
        }
    }

    /**
     * 递归函数,寻找所有拆分组合
     * @param target 当前需要拆分的数
     * @param current 当前组合
     * @param start 从哪个数开始尝试
     */
    public static void findCombinations(int target, List<Integer> current, int start) {
        // 如果target为0,表示找到了一种拆分方式
        if (target == 0) {
            // 避免保存数字本身这一特例
            if (current.size() > 1) {
                result.add(new ArrayList<>(current));
            }
            return;
        }

        // 从start开始尝试数字,保证组合中的数字递增
        for (int i = start; i <= target; i++) {
            current.add(i);
            findCombinations(target - i, current, i);
            current.remove(current.size() - 1); // 回溯
        }
    }
}

P1596 [USACO10OCT] Lake Counting S

解题思路

  • 数据输入与初始化:通过Scanner读取田地的大小NM,然后输入N行的水坑图,用二维字符数组field存储。我们还用visited二维布尔数组来标记某个位置是否已经访问过。

  • 主遍历逻辑

    • 使用两层循环遍历整个田地的每一个位置,检查是否为水坑('W')且未被访问过。如果满足条件,调用DFS函数进行深度优先搜索,将这个水坑的所有格子都标记为已访问。
  • DFS函数

    • 从当前位置开始,将当前位置标记为已访问,然后尝试向八个方向(上下左右及四个对角线)进行递归搜索。如果新的位置仍在田地范围内且是水坑并且未被访问过,继续递归搜索。
  • 输出结果:输出最终统计的水坑数量。

import java.util.Scanner;

public class Main {

    static int n, m;
    static char[][] field;          // 记录田地的水坑图
    static boolean[][] visited;     // 记录每个位置是否访问过
    static int[] dx = {-1, -1, -1, 0, 1, 1, 1, 0}; // 上, 左上, 左, 左下, 下, 右下, 右, 右上
    static int[] dy = {-1, 0, 1, 1, 1, 0, -1, -1}; // 对应的y坐标变化

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        n = input.nextInt();
        m = input.nextInt();
        field = new char[n][m];
        visited = new boolean[n][m];

        // 输入田地的水坑图
        for (int i = 0; i < n; i++) {
            field[i] = input.next().toCharArray();
        }

        int count = 0; // 记录水坑的数量

        // 遍历整个田地
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                // 如果是水坑,并且没有访问过
                if (field[i][j] == 'W' && !visited[i][j]) {
                    dfs(i, j); // 使用深度优先搜索标记整个水坑
                    count++; // 水坑数量加1
                }
            }
        }

        // 输出水坑的数量
        System.out.println(count);
    }

    // 深度优先搜索函数
    public static void dfs(int x, int y) {
        visited[x][y] = true; // 标记当前位置已访问

        // 尝试移动到八个相邻的格子
        for (int i = 0; i < 8; i++) {
            int nx = x + dx[i];
            int ny = y + dy[i];

            // 判断新位置是否在范围内,并且是水坑且未访问过
            if (nx >= 0 && nx < n && ny >= 0 && ny < m && field[nx][ny] == 'W' && !visited[nx][ny]) {
                dfs(nx, ny); // 递归继续访问相邻的水坑格子
            }
        }
    }
}

P1162 填涂颜色

解题思路

  • 首先从矩阵的边界出发,使用 DFS 或 BFS 遍历所有与边界连通的 0,将它们标记为外部区域(可以标记为 -1)。
  • 遍历矩阵中剩余的 0,这些 0 位于闭合圈内,将它们替换为 2
  • 最后,将标记为 -1 的外部区域恢复为 0,输出最终结果。
import java.util.Scanner;

public class Main {
    static int[][] matrix;    // 定义一个二维数组来存储矩阵
    static int n;

    // 定义四个方向
    static int[] dx = {-1, 1, 0, 0};    
    static int[] dy = {0, 0, -1, 1};

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        n = input.nextInt();
        matrix = new int[n][n];

        // 读入矩阵
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                matrix[i][j] = input.nextInt();
            }
        }

        // 从矩阵的边界开始DFS标记外部的0
        for (int i = 0; i < n; i++) {
            if (matrix[i][0] == 0) dfs(i, 0); // 左边界
            if (matrix[i][n - 1] == 0) dfs(i, n - 1); // 右边界
        }
        for (int j = 0; j < n; j++) {
            if (matrix[0][j] == 0) dfs(0, j); // 上边界
            if (matrix[n - 1][j] == 0) dfs(n - 1, j); // 下边界
        }

        // 把剩下的0替换成2,把标记为-1的外部0恢复为0
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (matrix[i][j] == 0) {
                    matrix[i][j] = 2; // 闭合圈内的0
                } else if (matrix[i][j] == -1) {
                    matrix[i][j] = 0; // 外部的0
                }
            }
        }

        // 输出结果
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                System.out.print(matrix[i][j] + " ");
            }
            System.out.println();
        }
    }

    // 使用DFS标记外部的0
    static void dfs(int x, int y) {
        matrix[x][y] = -1; // 标记为外部的0
        for (int i = 0; i < 4; i++) {
            int nx = x + dx[i];
            int ny = y + dy[i];
            // 如果新位置在矩阵范围内且值为0,则继续DFS
            if (nx >= 0 && nx < n && ny >= 0 && ny < n && matrix[nx][ny] == 0) {
                dfs(nx, ny);
            }
        }
    }
}

P1032 [NOIP2002 提高组] 字串变换

解题思路

  • BFS 初始化

    • 使用一个队列来存储当前字符串和当前步数的对 (current_string, step_count)
    • 同时使用一个集合来记录访问过的字符串状态,以避免重复状态的搜索(循环状态)。
  • 广度优先搜索

    • 每次从队列中取出一个字符串状态,检查是否已经变换为了目标字符串B。
    • 对当前字符串应用所有可能的变换规则,生成新的字符串状态并加入队列。
    • 如果应用了某条规则生成的新字符串已经访问过,则跳过。
    • 如果在10步内找到了目标字符串,输出变换的步数。
  • 终止条件

    • 如果队列为空且没有找到目标字符串B,则输出 "NO ANSWER!"。
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // 读取初始字符串和目标字符串
        String A = scanner.next();
        String B = scanner.next();
        
        // 读取转换规则
        List<Rule> rules = new ArrayList<>();
        while (scanner.hasNext()) {
            String a = scanner.next();
            String b = scanner.next();
            rules.add(new Rule(a, b));
        }
        
        // BFS 队列,队列中的每个元素为一个 Pair<当前字符串, 变换步数>
        Queue<Pair> queue = new LinkedList<>();
        queue.add(new Pair(A, 0));
        
        // 记录访问过的字符串状态,防止重复
        Set<String> visited = new HashSet<>();
        visited.add(A);
        
        // BFS 遍历
        while (!queue.isEmpty()) {
            Pair current = queue.poll();
            String currentString = current.string;
            int step = current.step;
            
            // 如果当前字符串已经是目标字符串,输出步数并退出
            if (currentString.equals(B)) {
                System.out.println(step);
                return;
            }
            
            // 如果超过10步,则停止搜索
            if (step >= 10) {
                continue;
            }
            
            // 对当前字符串尝试所有的转换规则
            for (Rule rule : rules) {
                int index = currentString.indexOf(rule.from);
                while (index != -1) {
                    // 生成新的字符串
                    String newString = currentString.substring(0, index) + rule.to + currentString.substring(index + rule.from.length());
                    
                    // 如果没有访问过这个新字符串状态,则加入队列
                    if (!visited.contains(newString)) {
                        queue.add(new Pair(newString, step + 1));
                        visited.add(newString);
                    }
                    
                    // 继续查找下一个匹配的位置
                    index = currentString.indexOf(rule.from, index + 1);
                }
            }
        }
        
        // 如果找不到答案
        System.out.println("NO ANSWER!");
    }
}

// 辅助类来存储字符串和步数
class Pair {
    String string;
    int step;
    
    Pair(String s, int step) {
        this.string = s;
        this.step = step;
    }
}

// 辅助类来存储变换规则
class Rule {
    String from;
    String to;
    
    Rule(String from, String to) {
        this.from = from;
        this.to = to;
    }
}

P1825 [USACO11OPEN] Corn Maze S

解题思路

1. 问题分析
  • 迷宫中有以下几种元素:
    • # 表示墙壁,无法通过。
    • . 表示空地,可以正常移动。
    • 大写字母 (A-Z) 表示传送门的两端,踏入其中一端会被立即传送到另一端。
    • = 表示出口,我们的目标是从 @ 移动到 =.
    • @ 表示起点,BFS 的起始位置。
  • 奶牛只能上下左右四个方向移动,每次移动花费 1 个时间单位。
  • 使用传送门从一个端点到另一个端点是瞬间完成的,不花费时间。
2. 解题策略

我们使用广度优先搜索(BFS)来解决这个问题。BFS 的特点是按层遍历,也就是说,当我们第一次到达终点时,一定是花费最少时间的路径。

BFS 的步骤:

  1. 初始化

    • 将起点放入队列,并标记为已访问。
    • 初始化方向数组 d,表示四个可能移动的方向。
  2. BFS 遍历

    • 从队列中取出当前节点,检查是否为终点,如果是终点则返回当前步数。
    • 如果当前节点是传送门(大写字母),则使用 findTeleport 方法找到对应的另一个传送门,将当前位置更新为传送门的另一端。
    • 尝试从当前节点向四个方向移动,如果新位置是空地且未访问过,则将该位置加入队列并标记为已访问。
  3. 终止条件

    • 当队列为空时,即搜索完所有可能的路径,结束搜索。如果此时还没到达终点,则说明没有路径(不过按题意保证有出口)。
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

public class Main {
    static int[][] maze = new int[500][500];  // 迷宫表示
    static boolean[][] visited = new boolean[500][500];  // 访问标记
    static int n, m;  // 行和列
    static int sx, sy;  // 起点坐标
    static int ex, ey;  // 终点坐标
    static int[][] d = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};  // 方向数组

    // 存储节点的类
    static class Node {
        int x, y, step;
        Node(int x, int y, int step) {
            this.x = x;
            this.y = y;
            this.step = step;
        }
    }

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        n = input.nextInt();
        m = input.nextInt();
        input.nextLine();  // 读取换行符

        char s;
        for (int i = 1; i <= n; i++) {
            String line = input.nextLine();
            for (int j = 1; j <= m; j++) {
                s = line.charAt(j - 1);
                if (s == '.') {
                    maze[i][j] = 1;  // 草地可以通过
                }
                if (s >= 'A' && s <= 'Z') {
                    maze[i][j] = s;  // 传送门,用字符表示
                }
                if (s == '@') {
                    sx = i;
                    sy = j;
                    maze[i][j] = 1;  // 起点
                }
                if (s == '=') {
                    ex = i;
                    ey = j;
                    maze[i][j] = 1;  // 终点
                }
            }
        }

        visited[sx][sy] = true;  // 标记起点为已访问
        bfs();  // 执行广度优先搜索
    }

    // 找到传送门的另一端
    static void findTeleport(Node node) {
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                // 找到与当前传送门字符相同且不是当前位置的传送门
                if ((i != node.x || j != node.y) && maze[i][j] == maze[node.x][node.y]) {
                    node.x = i;
                    node.y = j;
                    return;
                }
            }
        }
    }

    // 广度优先搜索
    static void bfs() {
        Queue<Node> queue = new LinkedList<>();
        queue.add(new Node(sx, sy, 0));  // 起点入队

        while (!queue.isEmpty()) {
            Node current = queue.poll();

            // 如果到达了终点
            if (current.x == ex && current.y == ey) {
                System.out.println(current.step);
                return;
            }

            // 如果当前位置是传送门
            if (maze[current.x][current.y] >= 'A' && maze[current.x][current.y] <= 'Z') {
                findTeleport(current);  // 找到传送门的另一端
            }

            // 尝试四个方向的移动
            for (int i = 0; i < 4; i++) {
                int nx = current.x + d[i][0];
                int ny = current.y + d[i][1];

                if (nx >= 1 && nx <= n && ny >= 1 && ny <= m && maze[nx][ny] != 0 && !visited[nx][ny]) {
                    visited[nx][ny] = true;  // 标记为已访问
                    queue.add(new Node(nx, ny, current.step + 1));  // 新节点入队,步数加 1
                }
            }
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2160943.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Go语言】深入解读Go语言中的指针,助你拨开迷雾见月明

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

浅谈提示工程之In-context learning技术

提示工程之In-context learning技术&#xff1b; 通过一张图片围绕下边几个方面进行简单说明 概念起因本质结构注意事项 日常总结

SQL语法学习与实战应用

第一章 引言 1.1 MySQL数据库概述 MySQL&#xff0c;作为一种广泛使用的关系型数据库管理系统&#xff0c;自其问世以来&#xff0c;便凭借开源、高性能及低成本等显著特点&#xff0c;迅速占据了广泛的市场份额。这一系统不仅支持大规模并发访问&#xff0c;更提供了多样化的…

【最新华为OD机试E卷-支持在线评测】绘图机器(100分)多语言题解-(Python/C/JavaScript/Java/Cpp)

🍭 大家好这里是春秋招笔试突围 ,一枚热爱算法的程序员 💻 ACM金牌🏅️团队 | 大厂实习经历 | 多年算法竞赛经历 ✨ 本系列打算持续跟新华为OD-E/D卷的多语言AC题解 🧩 大部分包含 Python / C / Javascript / Java / Cpp 多语言代码 👏 感谢大家的订阅➕ 和 喜欢�…

【ARM】MDK-当选择AC5时每次点击build都会全编译

1、 文档目标 解决MDK中选择AC5时每次点击build都会全编译 2、 问题场景 在MDK中点击build时&#xff0c;正常会只进行增量编译&#xff0c;但目前每次点击的时候都会全编译。 3、软硬件环境 1 软件版本&#xff1a;Keil MDK 5.38a 2 电脑环境&#xff1a;Window 10 4、解决…

新手操作指引:快速上手腾讯混元大模型

引言 腾讯混元大模型是一款功能强大的AI工具&#xff0c;适用于文本生成、图像创作和视频生成等多种应用场景。对于新手用户&#xff0c;快速上手并充分利用这一工具可能会有些挑战。本文将提供详细的新手操作指引&#xff0c;帮助您轻松开始使用腾讯混元大模型。 步骤一&…

kubernetes网络(二)之bird实现节点间BGP互联的实验

摘要 上一篇文章中我们学习了calico的原理&#xff0c;kubernetes中的node节点&#xff0c;利用 calico 的 bird 程序相互学习路由&#xff0c;为了加深对 bird 程序的认识&#xff0c;本文我们将使用bird进行实验&#xff0c;实验中实现了BGP FULL MESH模式让宿主相互学习到对…

个人行政复议在线预约系统开发+ssm论文源码调试讲解

第二章 开发工具及关键技术介绍 2.1 JAVA技术 Java主要采用CORBA技术和安全模型&#xff0c;可以在互联网应用的数据保护。它还提供了对EJB&#xff08;Enterprise JavaBeans&#xff09;的全面支持&#xff0c;java servlet API&#xff0c;JSP&#xff08;java server pages…

Pygame中Sprite实现逃亡游戏2

在《Pygame中Sprite实现逃亡游戏1》中实现了奔跑的玩家&#xff0c;接下来实现显示追赶玩家的飞龙以及对面过来的飞火。 1 显示飞龙 显示飞龙的代码如图1所示。 图1 显示飞龙的代码 其中&#xff0c;第93行代码创建了精灵类MySprite的实例dragon&#xff1b;第94行代码导入飞…

《十年国庆游,洞察中国旅游新趋势》

作者&#xff1a;侯炯 一、十年国庆旅游数据总览 过去十年&#xff0c;中国国庆旅游市场呈现出丰富的变化和强劲的发展态势。从接待游客人次来看&#xff0c;2014 年接待国内游客 4.75 亿人次&#xff0c;到 2019 年已增长至 7.82 亿人次&#xff0c;2023 年国内旅游出游人数更…

如何使用ssm实现新媒体视域下的中国古诗词展演+vue

TOC ssm678新媒体视域下的中国古诗词展演vue 绪论 课题背景 身处网络时代&#xff0c;随着网络系统体系发展的不断成熟和完善&#xff0c;人们的生活也随之发生了很大的变化。目前&#xff0c;人们在追求较高物质生活的同时&#xff0c;也在想着如何使自身的精神内涵得到提…

SpringBoot文档管理系统:架构与功能

第2章相关技术 2.1 Java技术介绍 Java语言擅长开发互联网类应用和企业级应用&#xff0c;现在已经相当的成熟&#xff0c;而且也是目前使用最多的编程语言之一。Java语言具有很好的面向对象性&#xff0c;可以符合人的思维模式进行设计&#xff0c;封装是将对象的属性和方法尽可…

FileLink:企业级跨网文件交换解决方案,效率与安全并存

在数字化转型的时代&#xff0c;企业面临着日益增长的文件交换需求。尤其是在跨网环境中&#xff0c;如何高效、安全地共享文件&#xff0c;成为企业运营的关键。FileLink 正是针对这一需求而生&#xff0c;为企业提供了一个高效、安全的文件交换解决方案。 一、FileLink的核心…

基本定时器的预分频器和技术周期的计算

从表中可见APB1和APB2他们的总线频率和时钟频率则是不一样的 APB1的总线频率是42MHZ 定时器的时钟频率则为84MHZ APB2的总线频率则为84MHZ 定时器则为168MHZ 如我们要使用某个寄存器则我们需要了解他们的定时器的频率则为多少 了解后则进行计算所需要的时间 列如:配置定时…

【CSS in Depth 2 精译_032】5.4 Grid 网格布局的显式网格与隐式网格(上)

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第一章 层叠、优先级与继承&#xff08;已完结&#xff09; 1.1 层叠1.2 继承1.3 特殊值1.4 简写属性1.5 CSS 渐进式增强技术1.6 本章小结 第二章 相对单位&#xff08;已完结&#xff09; 2.1 相对…

揭秘隐世秘学与千门八将的智慧,为什么说是你人生必学?

引言 在浩瀚的人类文化长河中&#xff0c;隐藏着无数神秘的隐世秘学&#xff0c;它们或源于古老的传说&#xff0c;或深植于民间的智慧之中。这些秘学不仅承载着人类对未知世界的探索与想象&#xff0c;更蕴含着丰富的哲理与策略。其中&#xff0c;“千门八将”以其独特的智慧体…

ITU标准引领车内通讯新纪元

在现代汽车科技更迭的今天&#xff0c;车内通讯与免提通话系统的性能与稳定性成为了消费者购车时不可忽视的重要因素。随着国际电信联盟&#xff08;ITU&#xff09;一系列标准的推出&#xff0c;车内通讯体验正迈向新的高度。本文将深入探讨ITU-T P.1100、P.1110、P.1120、P.1…

3D建模:Agisoft Metashape Professional 详细安装教程分享 Mac/win

Agisoft Metashape中文版&#xff08;以前称为 PhotoScan&#xff09;是一款独立软件产品&#xff0c;可对数字图像进行摄影测量处理并生成 3D 空间数据&#xff0c;用于 GIS 应用程序、文化遗产文献和视觉效果制作以及各种比例的物体的间接测量。 明智地实施数字摄影测量技术…

Qt/C++ 多线程同步机制详解及应用

在多线程编程中&#xff0c;线程之间共享资源可能会导致数据竞争和不一致的问题。因此&#xff0c;采用同步机制确保线程安全至关重要。在Qt/C中&#xff0c;常见的同步机制有&#xff1a;互斥锁&#xff08;QMutex、std::mutex&#xff09;、信号量&#xff08;QSemaphore&…

数据结构--单链表创建、增删改查功能以及与结构体合用

一、作业要求 单链表操作&#xff0c;要求节点是结构体类型&#xff0c;实现以下功能&#xff1a; 1.尾插学生 2.任意位置插入学生 3.任意位置删除学生 4.逆置单链表 5.学生按学号排序 6.销毁单链表 二、实现过程 1.代码如下&#xff1a; &#xff08;1&#xff09;头…