动态规划求二维网格中从左上角到右下角的最短路径( 每次只能向下、向右、向右下走 ) java 实现

dp[i][j] 表示在以点(0,0)作为左上角,点(i,i) 作为右下角的二维网格中 左上角到右下角的最短路径,
动态转移方程为:dp[i][j] = min{ dp[i][j-1],dp[i-1][j],dp[i-1][j-1] }.distance + weight[i][j]

ImageUtils.java:



import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import javax.imageio.ImageIO;

public class ImageUtils {

    /**
     *
     * @param mat
     * @param outputPath
     * @param cellSize 格子的边长
     */
    public static void printMat2Image(int[][] mat, String outputPath,int cellSize,PathVO path) {
        // 总行数
        int rowCount = mat.length;

        // 总列数
        int colCount = mat[0].length;

        int fontSize = cellSize / 2;
        BufferedImage image = new BufferedImage(colCount * cellSize, rowCount * cellSize, BufferedImage.TYPE_INT_RGB);
        Graphics g = image.getGraphics();
        Random random = new Random();

        // 设置背景色为白色
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, colCount * cellSize, rowCount * cellSize);

        // 画网格
        g.setColor(Color.BLACK);
        for (int i = 0; i <= rowCount; i++) {
            g.drawLine(0, i * cellSize, colCount * cellSize, i * cellSize);
        }
        for (int i = 0; i <= colCount; i++) {
            g.drawLine(i * cellSize, 0, i * cellSize, rowCount * cellSize);
        }

        Set<String> codes = new HashSet<>();
        List<PointVO> points = path.getPoints();
        for( PointVO point:points ){
            codes.add( point.getRowNum() + "_" + point.getColNum() );
        }

     /*   Color color = g.getColor();
        // 画路径
        List<PointVO> points = path.getPoints();
        g.setColor( Color.GREEN );
        for( PointVO point:points ){
            int x = point.getRowNum() * cellSize;
            int y = point.getColNum() * cellSize;
            g.fillRect(x, y, cellSize, cellSize); // 填充矩形
        }
        g.setColor( color );*/

        // 写入文本
        g.setFont(new Font("Arial", Font.BOLD, fontSize));
        Color color_old = g.getColor();
        Color color_green = Color.GREEN;
        FontMetrics fontMetrics = g.getFontMetrics();
        for (int rowNum = 0; rowNum < rowCount; rowNum++) {
            int[] row = mat[rowNum];
            for (int colNum = 0; colNum < colCount; colNum++) {
                int num = row[colNum];
                String code = rowNum + "_" + colNum;
                if( codes.contains( code ) ){
                    g.setColor( color_green );
                }else {
                    g.setColor( color_old );
                }
                String text = String.valueOf( num );
                int x = colNum * cellSize + (cellSize - fontMetrics.stringWidth(text) ) / 2;
                int y = rowNum * cellSize + (cellSize - fontMetrics.getHeight()) / 2 + fontMetrics.getAscent();
                g.drawString(text, x, y);
            }
        }

        // 输出图片
        try {
            ImageIO.write(image, "png", new File(outputPath));
            System.out.println("图片已生成:" + outputPath);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

PathVO.java:


import lombok.Getter;
import lombok.Setter;

import java.io.Serializable;
import java.util.List;


@Getter
@Setter
public class PathVO implements Serializable {

    private List<PointVO> points;
    private Integer distance;

}

PointVO.java:


import lombok.Getter;
import lombok.Setter;

import java.io.Serializable;


@Getter
@Setter
public class PointVO implements Serializable {
    private Integer rowNum;
    private Integer colNum;

    public PointVO(Integer rowNum, Integer colNum) {
        this.rowNum = rowNum;
        this.colNum = colNum;
    }
}

Test.java:


import lombok.Getter;
import lombok.Setter;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;



@Getter
@Setter
public class Test   {

    public static void main(String[] args) {
        test();
    }

    private static void test(){
     /*   int rowCount = 10;
        int colCount = 10;*/
        // int[][] mat = initRandomWeightMat( rowCount,colCount );
        int[][] mat = new int[][]{
                                    { 9, 9, 9, 9, 9, 9 },
                                    { 9, 1, 9, 9, 9, 9 },
                                    { 9, 1, 1, 9, 9, 9 },
                                    { 9, 1, 9, 1, 9, 9 },
                                    { 9, 1, 1, 1, 9, 1 },
                                    { 9, 9, 9, 9, 1, 9 }
                                };

        // dp[i][j] 表示在以点(0,0)作为左上角,点(i,i) 作为右下角的二维网格中 左上角到右下角的最短路径,
        // 动态转移方程为:dp[i][j] = min{ dp[i][j-1],dp[i-1][j] }.distance + weight[i][j]
        int rowCount = mat.length;
        int colCount = mat[0].length;

        PathVO[][] dp = new PathVO[rowCount][colCount];
        PathVO path = new PathVO();
        List<PointVO> points = new ArrayList<>();
        points.add( new PointVO( 0,0 ) );
        path.setPoints( points );
        path.setDistance( mat[0][0] );
        dp[0][0] = path;
        for (int colNum = 1; colNum < colCount; colNum++) {
            int rowNum = 0;
            int weight = mat[rowNum][colNum];
            PathVO path_prev = dp[rowNum][colNum - 1];
            path = new PathVO();
            points = new ArrayList<>();
            points.addAll( path_prev.getPoints() );
            points.add( new PointVO( rowNum,colNum ) );
            path.setPoints( points );
            path.setDistance( path_prev.getDistance() + weight );
            dp[rowNum][colNum] = path;
        }
        for (int rowNum = 1; rowNum < rowCount; rowNum++) {
            int colNum = 0;
            int weight = mat[rowNum][colNum];
            PathVO path_prev = dp[rowNum-1][colNum];
            path = new PathVO();
            points = new ArrayList<>();
            points.addAll( path_prev.getPoints() );
            points.add( new PointVO( rowNum,colNum ) );
            path.setPoints( points );
            path.setDistance( path_prev.getDistance() + weight );
            dp[rowNum][colNum] = path;
        }

        for (int rowNum = 1; rowNum < rowCount; rowNum++) {
            for (int colNum = 1; colNum < colCount; colNum++) {
                Integer weight = mat[ rowNum ][colNum];
                path = new PathVO();
                points = new ArrayList<>();

                // 当前点要么从上面的点到达,要么从 左边的点到达
                PathVO path_prev_up = dp[ rowNum -1 ][colNum];
                PathVO path_prev_left = dp[ rowNum ][colNum-1];
                PathVO path_prev_left_up = dp[ rowNum-1 ][colNum-1];
                PathVO path_prev_min = path_prev_up;
                if( path_prev_left.getDistance() < path_prev_min.getDistance() ){
                    path_prev_min = path_prev_left;
                }
                if( path_prev_left_up.getDistance() < path_prev_min.getDistance() ){
                    path_prev_min = path_prev_left_up;
                }
                points.addAll( path_prev_min.getPoints() );
                points.add( new PointVO( rowNum,colNum ) );
                path.setDistance( path_prev_min.getDistance() +  weight );
                path.setPoints( points );
                dp[ rowNum ][colNum] = path;
            }
        }
        path = dp[ rowCount -1 ][colCount -1];
        String outputPath = "C:\\E\\xxx.png";
        ImageUtils.printMat2Image( mat,outputPath,40,path );
    }

    private static int[][] initRandomWeightMat(int rowCount, int colCount) {
        Random random = new Random();
        // 初始化 二维网格矩阵
        int[][] mat = new int[rowCount][colCount];
        for (int rowNum = 0; rowNum < rowCount; rowNum++) {
            for (int colNum = 0; colNum < colCount; colNum++) {
                mat[ rowNum ][colNum] = random.nextInt( 2 ) + 1;
            }
        }
        return mat;
    }
}

测试输出:

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

凸问题与非凸问题

凸函数&#xff1a;曲线上任意两点连线上的点对应的函数值不大于该两点对应的函数值得连线上的值&#xff0c;例如yx^2&#xff1b; 非凸函数&#xff1a;曲线上任意两点连线上的点对应的函数值既有大于该两点对应的函数值得连线上的值的部分也有小于的部分&#xff0c;例如&am…

filebeat配置解析【待续】

目录 filebeat概览filebeat是如何工作的工作原理采集日志注册表发送日志 容器日志采集的三种方式方式一&#xff1a;Filebeat 与 应用运行在同一容器&#xff08;不推荐&#xff09;方式二&#xff1a;Filebeat 与 应用运行不在同一容器方式三&#xff1a;通过 Kubernetes File…

springboot使用redis缓存乱码(key或者 value 乱码)一招解决

如果查看redis中的值是这样 创建一个配置类就可以解决 package com.deka.config;import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; i…

最新EasyRecovery14中文版安装下载步骤

EasyRecovery是一款功能强大的数据恢复软件&#xff0c;可以一直免费使用下去&#xff0c;可以将受损的文件恢复过来&#xff0c;也可以检索数据格式化或损坏卷&#xff0c;还可以初始化磁盘。它拥有强大的数据恢复能力和快速地查找恢复机制&#xff0c;非常的简洁实用。拥有4大…

2023年亚太数学建模C题数据分享+详细思路

在报名截止的前一天&#xff0c;我尝试进行了报名。到那时&#xff0c;已有11,000个队伍注册参赛。在我的了解中&#xff0c;在数模比赛中除了国赛美赛外&#xff0c;几乎没有其他竞赛的参赛队伍数量能与此相媲美。即便不考虑赛题的难度和认可度&#xff0c;亚太地区的这场竞赛…

Java中的字符串String

目录 一、常用方法 1、字符串构造 2、String对象的比较 &#xff08;1&#xff09;、equals方法 &#xff08;2&#xff09;、compareTo方法 &#xff08;3&#xff09;、compareToIgnoreCase方法&#xff08;忽略大小写进行比较&#xff09; 3、字符串查找 4、转化 &…

盘点一下:为了考上本科,你需要放弃什么?

专转本除了胜利后喜悦&#xff0c;更多的则是过程的艰辛&#xff0c;为了专转本成功&#xff0c;我们放弃了自己的娱乐时间、放弃了自己的兴趣爱好。 专转本考试相当于人生第二次“高考”&#xff0c;在学历门槛的今天&#xff0c;越来越多的人都在通过各类途径提转个人学历。…

基准电压源的工作原理和作用是什么(高精度电压源)

基准电压源是一种能够提供固定、稳定的直流电压输出的电源设备。它广泛应用于精密仪器、测试设备、通信设备等领域&#xff0c;是实现精确电压测量和校准的重要工具。本文将为您介绍基准电压源的工作原理和作用。 一、基准电压源的工作原理 基准电压源采用了高精度的电路设计和…

【数据结构】深入浅出理解链表中二级指针的应用

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:数据结构 ⚙️操作环境:Visual Studio 2022 (注:为方便演示本篇使用的x86系统,因此指针的大小为4个字节) 目录 &#x1f4cc;形参的改变不影响实参! 1.调用函数更改整型时传值调用与传址调用的区别 &#x1f38f;传值…

【23真题】最后一套两电一邮,纸老虎偏多!

今天分享的是23年西安电子科技大学811的信号与系统试题及解析。更新完这套&#xff0c;两电一邮的全部23真题已更新完毕&#xff01; 本套试卷难度分析&#xff1a;22年西电811考研真题&#xff0c;我发布过&#xff0c;若有需要戳这里自取&#xff01;这里统计了811的上岸平均…

Linux本地MinIO存储服务远程调用上传文件

&#x1f525;博客主页&#xff1a; 小羊失眠啦. &#x1f3a5;系列专栏&#xff1a;《C语言》 《数据结构》 《Linux》《Cpolar》 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 文章目录 前言1. 创建Buckets和Access Keys2. Linux 安装Cpolar3. 创建连接MinIO服务公网地址4. …

数据结构算法-贪心算法

引言 贪心&#xff1a;人只要有 “需求“ &#xff0c;都会有有点“贪“&#xff0c; 这种“贪“是一种选择&#xff0c;或者“”取舍“ RTS&#xff08;即时战略&#xff09;游戏&#xff1a; 帝国时代里 首先确保拥有足够的人口 足够的粮食&#xff0c;足够的战略资源 足够的…

【linux】服务器CPU占用50%,top/htop/ps却看不到异常进程?使用unhide可以查看!

问题描述 htop发现前32个核全被占满了&#xff0c;但是却找不到对应进程号 查杀 安装unhide查看隐藏进程 apt-get install unhideunhide使用 unhide proc果然发现了隐藏进程 杀死隐藏进程 kill -9 [pid]这么多pid号&#xff0c;我这边杀了其中一个&#xff0c;发现CPU…

Docker 安装 Apache

目录 拉取官方 Apache 镜像 查看本地镜像 列出正在运行的容器 运行 Apache 容器 创建一个 HTML 文件&#xff1a;index.html 访问 Apache 拉取官方 Apache 镜像 查找 Docker Hub 上的 httpd 镜像。 可以通过 Tags 查看其他版本的 httpd&#xff0c;默认是最新版本 httpd…

vue2.0+elementui集成file-loader之后图标失效问题

背景 跑vue2elementUI项目时&#xff0c;由于前端这边需要在本地存放xlsx模板文件&#xff0c;供用户下载模板文件&#xff0c;所以需要在webpack构建的时候增加file-loader进行解析xlsx文件打包。 vue版本2.x element-ui 版本 2.13.x 注意 npm i -D file-loader版本号给vue项…

史诗级云故障敲响警钟,应用保障不能没有“连续键”!

近日&#xff0c;知名云服务商出现一次史诗级的云故障&#xff1a;全球所有区域/所有服务同时异常&#xff0c;故障持续长达3小时之多&#xff0c;云上众多应用受到极大影响。 如今&#xff0c;在一个充满不确定性和复杂性的数字化时代&#xff0c;哪怕是顶级云服务商亦不能避…

3.7寸墨水屏蓝牙卡证

超薄机身&#xff0c;厚度不足一厘米&#xff0c;轻松佩戴无负重感。 无需基站&#xff0c;服务器&#xff0c;手机APP直接更新~ 独创快速扫描技术&#xff0c;智能感应标签 超长待机&#xff0c;超低功耗&#xff0c;Type C接口充电&#xff0c;一次充电可续航一年&#xf…

docker安装以及idea访问docker

其他目录&#xff1a; docker 安装环境&#xff08;有空更新&#xff09; url “” docker 打包java包&#xff0c;并运行&#xff08;有空更新&#xff09; url “” docker 打包vue &#xff08;有空更新&#xff09; url “” docker 多服务 &#xff08;有空更新&#xff…

PC8259(CC-CV控制)同步降压芯片5V/4.8A 输出频率可调 带电流限制 QFN20封装

概述 PC8259是一个同步降压转换器输出电流为4.8A在9V至36V。外部关闭功能可以由逻辑电平控制以下拉COMP/EN引脚&#xff0c;然后进入待机模式。外部补偿使反馈控制具有良好的线性以及具有灵活外部设计的负载调节。PC8259在CC&#xff08;恒定输出电流&#xff09;模式或CV&…

一篇文章,教你看懂加密工具The Enigma Protector

The Enigma Protector作为一款专业的软件授权和保护工具&#xff0c;一直以来深受开发者喜爱&#xff0c;此次携手慧都合作上线&#xff0c;更加方便了国内用户的购买和使用&#xff0c;一起来看看这款工具都有哪些值得期待的地方↓↓↓ The Enigma Protector 是一款专门设计用…