代码随想录打卡|Day53 图论(Floyd 算法精讲 、A * 算法精讲 (A star算法)、最短路算法总结篇、图论总结 )

图论part11

Floyd 算法精讲

代码随想录链接
题目链接

代码

三维DP数组
java 复制代码
import java.util.Scanner;

public class Main {
    // 定义最大距离值,避免使用Integer.MAX_VALUE防止加法溢出
    public static final int INF = 100000000; // 10^8足够大且不会溢出

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        
        /* 
         * 1. 输入处理
         * 第一行:N(景点数量), M(道路数量)
         * 接下来M行:u, v, w (双向道路)
         * 然后一行:Q(查询数量)
         * 接下来Q行:start, end (查询起点和终点)
         */
        int n = sc.nextInt(); // 景点数量 (1到n编号)
        int m = sc.nextInt(); // 道路数量
        
        /*
         * 2. 初始化三维DP数组
         * dp[k][i][j]表示从i到j,允许经过前k个节点(1..k)的最短路径
         * 这里k的范围是0到n:
         * - k=0表示不允许经过任何中间节点(直接边)
         * - k=n表示允许经过所有节点
         */
        int[][][] dp = new int[n+1][n+1][n+1];
        
        // 初始化所有距离为INF,自己到自己的距离为0
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                for (int k = 0; k <= n; k++) {
                    if (i == j) {
                        dp[k][i][j] = 0; // 自己到自己的距离为0
                    } else {
                        dp[k][i][j] = INF; // 初始化为最大值
                    }
                }
            }
        }
        
        // 3. 读取道路信息并填充初始距离(k=0的情况)
        for (int i = 0; i < m; i++) {
            int u = sc.nextInt();
            int v = sc.nextInt();
            int w = sc.nextInt();
            // 双向道路,两个方向都要设置
            dp[0][u][v] = w;
            dp[0][v][u] = w;
        }
        
        /* 
         * 4. Floyd-Warshall算法核心部分(三维DP版本)
         * 状态转移方程:
         * dp[k][i][j] = min(dp[k-1][i][j], dp[k-1][i][k] + dp[k-1][k][j])
         * 含义:
         * - 从i到j允许经过前k个节点的最短路径 =
         *   min(不经过k的最短路径, 经过k的最短路径)
         */
        for (int k = 1; k <= n; k++) {         // 中间节点
            for (int i = 1; i <= n; i++) {     // 起点
                for (int j = 1; j <= n; j++) { // 终点
                    // 比较两种情况:
                    // 1. 不经过节点k的最短路径(dp[k-1][i][j])
                    // 2. 经过节点k的最短路径(dp[k-1][i][k] + dp[k-1][k][j])
                    dp[k][i][j] = Math.min(dp[k-1][i][j], dp[k-1][i][k] + dp[k-1][k][j]);
                }
            }
        }
        
        // 5. 处理查询
        int q = sc.nextInt(); // 查询数量
        for (int i = 0; i < q; i++) {
            int start = sc.nextInt();
            int end = sc.nextInt();
            // 使用允许经过所有节点(n个)的最短路径作为结果
            // 如果不可达则输出-1
            System.out.println(dp[n][start][end] == INF ? -1 : dp[n][start][end]);
        }
    }
}
二维DP数组
java 复制代码
import java.util.Scanner;

public class Main {
    // 定义最大距离值,避免使用Integer.MAX_VALUE防止加法溢出
    public static final int INF = 100000000; // 10^8足够大且不会溢出

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        
        // 1. 读取景点数量和道路数量
        int n = sc.nextInt(); // 景点数量 (1到n编号)
        int m = sc.nextInt(); // 道路数量
        
        // 2. 初始化距离矩阵
        int[][] dist = new int[n+1][n+1]; // 1-based索引
        
        // 初始化所有距离为INF,自己到自己的距离为0
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                if (i == j) {
                    dist[i][j] = 0;
                } else {
                    dist[i][j] = INF;
                }
            }
        }
        
        // 3. 读取道路信息并填充初始距离
        for (int i = 0; i < m; i++) {
            int u = sc.nextInt();
            int v = sc.nextInt();
            int w = sc.nextInt();
            // 双向道路,两个方向都要设置
            dist[u][v] = w;
            dist[v][u] = w;
        }
        
        // 4. Floyd-Warshall算法核心部分
        for (int k = 1; k <= n; k++) {         // 中间节点
            for (int i = 1; i <= n; i++) {     // 起点
                for (int j = 1; j <= n; j++) { // 终点
                    // 如果通过中间节点k可以缩短i到j的距离
                    if (dist[i][k] + dist[k][j] < dist[i][j]) {
                        dist[i][j] = dist[i][k] + dist[k][j];
                    }
                }
            }
        }
        
        // 5. 处理查询
        int q = sc.nextInt(); // 查询数量
        for (int i = 0; i < q; i++) {
            int start = sc.nextInt();
            int end = sc.nextInt();
            // 输出结果,如果不可达则输出-1
            System.out.println(dist[start][end] == INF ? -1 : dist[start][end]);
        }
    }
}

A * 算法精讲 (A star算法)

代码随想录链接
题目链接

代码(超时,示例正确)

java 复制代码
import java.util.*;

public class Main {
    
    // 定义骑士的8种可能移动方式(马走日)
    private static final int[][] MOVES = {
        {1, 2}, {2, 1}, {2, -1}, {1, -2},
        {-1, -2}, {-2, -1}, {-2, 1}, {-1, 2}
    };
    
    // 节点类,表示棋盘上的一个位置
    static class Node implements Comparable<Node> {
        int x, y;        // 当前位置坐标
        int g;           // 从起点到当前节点的实际代价
        int h;           // 到目标节点的启发式估计代价
        Node parent;      // 父节点(用于路径回溯)
        
        public Node(int x, int y) {
            this.x = x;
            this.y = y;
            this.g = 0;
            this.h = 0;
        }
        
        // 计算总代价f = g + h
        public int f() {
            return g + h;
        }
        
        // 用于优先队列排序
        @Override
        public int compareTo(Node other) {
            return Integer.compare(this.f(), other.f());
        }
        
        // 重写equals和hashCode用于比较节点
        @Override
        public boolean equals(Object obj) {
            if (this == obj) return true;
            if (obj == null || getClass() != obj.getClass()) return false;
            Node node = (Node) obj;
            return x == node.x && y == node.y;
        }
        
        @Override
        public int hashCode() {
            return Objects.hash(x, y);
        }
    }
    
    // A*算法实现
    public static int aStarKnightPath(int startX, int startY, int targetX, int targetY) {
        // 如果起点就是终点,直接返回0
        if (startX == targetX && startY == targetY) {
            return 0;
        }
        
        // 边界检查
        if (!isValid(startX, startY) || !isValid(targetX, targetY)) {
            return -1;
        }
        
        // 初始化开放列表和关闭列表
        PriorityQueue<Node> openList = new PriorityQueue<>();
        Set<Node> closedList = new HashSet<>();
        
        // 创建起点节点
        Node startNode = new Node(startX, startY);
        startNode.g = 0;
        startNode.h = heuristic(startX, startY, targetX, targetY);
        openList.add(startNode);
        
        while (!openList.isEmpty()) {
            // 获取当前最优节点
            Node currentNode = openList.poll();
            
            // 如果到达目标节点,返回步数
            if (currentNode.x == targetX && currentNode.y == targetY) {
                return currentNode.g;
            }
            
            // 将当前节点加入关闭列表
            closedList.add(currentNode);
            
            // 遍历所有可能的移动
            for (int[] move : MOVES) {
                int newX = currentNode.x + move[0];
                int newY = currentNode.y + move[1];
                
                // 检查新位置是否有效
                if (!isValid(newX, newY)) {
                    continue;
                }
                
                // 创建新节点
                Node neighbor = new Node(newX, newY);
                neighbor.g = currentNode.g + 1;  // 每步代价为1
                neighbor.h = heuristic(newX, newY, targetX, targetY);
                neighbor.parent = currentNode;
                
                // 如果已经在关闭列表中,跳过
                if (closedList.contains(neighbor)) {
                    continue;
                }
                
                // 检查是否在开放列表中
                boolean inOpenList = false;
                for (Node node : openList) {
                    if (node.equals(neighbor)) {
                        inOpenList = true;
                        // 如果找到更优路径,更新节点
                        if (neighbor.g < node.g) {
                            node.g = neighbor.g;
                            node.parent = currentNode;
                        }
                        break;
                    }
                }
                
                // 如果不在开放列表中,加入
                if (!inOpenList) {
                    openList.add(neighbor);
                }
            }
        }
        
        // 如果开放列表为空且未找到路径,返回-1
        return -1;
    }
    
    // 启发式函数:曼哈顿距离除以3(骑士每步最多移动3格)
    private static int heuristic(int x1, int y1, int x2, int y2) {
        return (Math.abs(x1 - x2) + Math.abs(y1 - y2)) / 3;
    }
    
    // 检查坐标是否有效
    private static boolean isValid(int x, int y) {
        return x >= 1 && x <= 1000 && y >= 1 && y <= 1000;
    }
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        
        for (int i = 0; i < n; i++) {
            int a1 = sc.nextInt();
            int a2 = sc.nextInt();
            int b1 = sc.nextInt();
            int b2 = sc.nextInt();
            
            int steps = aStarKnightPath(a1, a2, b1, b2);
            System.out.println(steps);
        }
    }
}

最短路算法总结篇

代码随想录链接


图论总结篇

代码随想录链接


相关推荐
小指纹1 小时前
2025山东CCPC题解
c++·算法
PixelMind5 小时前
【LUT技术专题】图像自适应3DLUT
图像处理·深度学习·算法·3dlut
木子.李3475 小时前
数据结构-算法学习C++(入门)
数据库·c++·学习·算法
GIS小天5 小时前
AI预测3D新模型百十个定位预测+胆码预测+去和尾2025年5月31日第94弹
人工智能·算法·机器学习·彩票
武子康6 小时前
大数据-274 Spark MLib - 基础介绍 机器学习算法 剪枝 后剪枝 ID3 C4.5 CART
大数据·人工智能·算法·机器学习·语言模型·spark-ml·剪枝
爱coding的橙子8 小时前
每日算法刷题Day19 5.31:leetcode二分答案3道题,用时1h
算法·leetcode·职场和发展
地平线开发者9 小时前
征程 6EM 常见 QConfig 配置解读与示例
算法·自动驾驶
GEEK零零七10 小时前
Leetcode 1908. Nim 游戏 II
算法·leetcode·博弈论
sbc-study10 小时前
混沌映射(Chaotic Map)
开发语言·人工智能·python·算法
Magnum Lehar10 小时前
vulkan游戏引擎game_types.h和生成build.bat实现
java·算法·游戏引擎