蓝桥杯每日一题----区间dp

前言

暂时没啥好说的,直接进入正题吧

引入

涂色PAINT


读题发现要求的是使一段区间满足要求的最小操作次数,考虑用动态规划去做。
第一步:考虑缩小规模,这里的规模其实就是区间长度,那么dp数组应该可以表示某个区间,所以到这里dp数组至少是二维的,也就是dp[i][j],表示让区间[i,j]合法的最小操作次数。
第二步:考虑限制,这里暂时看不出来有啥限制,那就先不管。
第三步:根据写出来的dp数组推转移方程,dp[i][j]可以从三个地方转移dp[i-1][j],dp[i][j-1],dp[i-1][j-1],考虑这三个转移有什么特点,假设我现在已经求出了dp[i-1][j-1]的染色次数,那么当s[i]=s[j]时,我只需要在对dp[i-1][j-1]染色之前,把区间[i,j]进行一次涂色,涂成s[i]的颜色,这样再执行dp[i-1][j-1]得到的就是对区间[i,j]染成了要求的颜色,那么染色次数dp[i][j]=dp[i-1][j-1]+1;假设我现在已经求出了dp[i-1][j]的染色次数,那么当s[i]=s[j]时,我只需要在对第j个木板进行染色时同时捎带着把第i个木板染了就行,那么染色次数dp[i][j]=dp[i-1][j];假设我现在已经求出了dp[i][j-1]的染色次数,那么当s[i]=s[j]时,我只需要在对第i个木板进行染色时同时捎带着把第j个木板染了就行,那么染色次数dp[i][j]=dp[i][j-1];可以考虑三者取最小值。
综上,当s[i]=s[j]时,dp[i][j]=min(dp[i-1][j-1]+1,dp[i][j-1],dp[i-1][j])
那么当s[i]!=s[j]时,没有办法直接求这个大区间,那么就从小区间考虑,即断开区间。假设断点是k,分别求dp[i][k]和dp[k+1][j],再加起来即可,对于不同的断点取最小值。
第四步:考虑要写代码了,这里要注意一下dp数组如何初始化,我们可以明确的知道,区间长度为1时,所需要的操作次数就是1,所以初始化区间长度为1的值。我们要求的是最小值,其它位置上的值可以初始化为一个较大的值,也可以直接是0,但是在求解过程中要特判一下。
第五步:考虑区间dp的板子,区间dp一般三层for循环,第一层遍历区间长度,一般由2开始。
第二层遍历区间左端点,根据区间左端点和区间长度,区间右端点也就出来了。
第三层遍历区间断点。
这道题目就分析完了,还是给了两个版本的代码,一个是我初学时写的,一个是现在写的,都能AC,但是现在写的更规范一点

package java动态规划;

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

public class ok涂色 {
public static void main(String[] args) {
	Scanner scanner = new Scanner(System.in);
	char s[] = (" "+scanner.next()).toCharArray();
	int n = s.length-1;
	int dp[][] = new int[n+1][n+1];
	for(int i = 0;i <= n;i++) Arrays.fill(dp[i], Integer.MAX_VALUE/2);
	for(int i = 0;i <= n;i++) dp[i][i] = 1;
	for(int len = 2;len <= n;len++) {
		for(int l = 1;l+len-1<=n;l++) {
			int r = len+l-1;
			if(s[l]==s[r]) dp[l][r] = Math.min(dp[l+1][r], dp[l][r-1]);
			else {
				for(int k = l;k < r;k++)
					dp[l][r] = Math.min(dp[l][r], dp[l][k]+dp[k+1][r]);
			}
		}
	}
	System.out.println(dp[1][n]);
}
}
import java.util.Scanner;
public class Main {
	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		String string = scanner.next();
		char[] s = string.toCharArray();
		int[][] dp = new int[string.length()][string.length()];
		// 初始化
		for (int i = 0; i < dp.length; i++) {
			dp[i][i] = 1;
		}

		for (int i = 1; i < string.length(); i++) {
			for (int j = 0; j + i < string.length(); j++) {
				int l = j;
				int r = j + i;
				if (s[l] == s[r]) {
					dp[l][r] = Math.min(dp[l + 1][r], dp[l][r - 1]);
				} else {
					for (int k = l; k < r; k++) {
						if (dp[l][r] != 0) {
							dp[l][r] = Math.min(dp[l][k] + dp[k + 1][r], dp[l][r]);
						} else {
							dp[l][r] = dp[l][k] + dp[k + 1][r];
						}
					}
				}
			}
		}
		System.out.println(dp[0][string.length() - 1]);
	}
}

例题2

合并回文子串

这道题稍微难一点,关键在于要想到用区间dp去做,并且明确区间是谁。我们要合并字符串A和B,那么可以考虑一点一点的合并,比如A的某个区间和B的某个区间进行合并。
第一步:考虑规模,这里的规模就是要合并的两个字符串,那么其实也就是有两个区间,字符串A的区间和字符串B的区间,那么dp数组就是四维的,dp[i][j][k][l]表示将字符串Ai-Aj与字符串Bk-Bl是否能形成回文串,如果可以那么回文串的长度就是(j-i+1)+(l-k+1).
第二步:考虑限制,限制就是不能更改原串字符的相对顺序,但是这里不知道怎么加在dp数组中,暂时一放。
第三步:推状态转移方程
对于dp[i][j][k][l],考虑一下如果怎么变成回文,i和j可以是对应的回文,j和k也可以是对应的回文,i和l可以是对应的回文,k和l可以是对应的回文。
那么考虑i和k可以是对应的回文吗?若可以,那么位置k必然是在l的右边,这样就打乱了数组B的原始顺序,所以是不可以的,其它非法方案也是类似。
若A[i]=A[j],则dp[i][j][k][l]可以从dp[i-1][j-1][k][l]转移过来,我只是想判断这种情况是否是回文,若是则为1,否则则为0,所以转移的时候可以直接用或运算转移,即dp[i][j][k][l]|=dp[i-1][j-1][k][l]。其他情况类似,于是有这样的转移方程,
若A[i]=A[j],则dp[i][j][k][l]|=dp[i+1][j-1][k][l]
若A[j]=A[k],则dp[i][j][k][l]|=dp[i][j][k+1][l-1]
若A[i]=A[l],则dp[i][j][k][l]|=dp[i+1][j][k][l-1]
若A[k]=A[j],则dp[i][j][k][l]|=dp[i][j+1][k-1][l]
当相等的情况不满足时,其实也就是无法构成回文,不必考虑。
第四步:考虑写代码,这里有两个区间,所以前两个for循环分别表示两个区间的长度,后两个for循环分别表示区间的左端点,因为这里没有断开区间操作,所以不用遍历断点。这里在写的时候注意是从区间长度为0开始遍历的,当总区间长度小于等于1时必然是回文,也就是len1+len2<=1时,直接是dp[i][j][k][l]=1。当然也可以预处理出来总长度为1的情况,但是不要漏处理了。

参考代码

import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int t = scanner.nextInt();
        while (t > 0) {
            t--;
            String a = scanner.next();
            String b = scanner.next();
            int n1 = a.length();
            int n2 = b.length();
            int dp[][][][] = new int[n1 + 5][n1 + 5][n2 + 5][n2 + 5];
            a = " " + a + " ";
            b = " " + b + " ";
            int res = 0;
            for (int len1 = 0; len1 < n1 + 1 ; len1++) {
                for (int len2 = 0; len2 < n2 + 1; len2++) {
                    for (int l1 = 1, r1 = len1 + l1 - 1; r1 < n1 + 1; l1++, r1++) {
                        for (int l2 = 1, r2 = len2 + l2 - 1; r2 < n2 + 1; l2++, r2++) {
//                      int r1 = len1+l1-1;
//                      int r2 = len2+l2-1;
                            if (len1 + len2 <= 1) {
                                dp[l1][r1][l2][r2] = 1;
                            } else {
                                if (r2 > 0 && a.charAt(l1) == b.charAt(r2))
                                    dp[l1][r1][l2][r2] |= dp[l1 + 1][r1][l2][r2 - 1];
                                if (r1 > 0 && a.charAt(r1) == b.charAt(l2))
                                    dp[l1][r1][l2][r2] |= dp[l1][r1 - 1][l2 + 1][r2];
                                if (r1 > 0 && a.charAt(l1) == a.charAt(r1))
                                    dp[l1][r1][l2][r2] |= dp[l1 + 1][r1 - 1][l2][r2];
                                if (r2 > 0 && b.charAt(l2) == b.charAt(r2))
                                    dp[l1][r1][l2][r2] |= dp[l1][r1][l2 + 1][r2 - 1];

                                if (dp[l1][r1][l2][r2] == 1) {
                                    res = Math.max(res, len1 + len2);
                                }
                            }

                        }
                    }
                }
            }
            System.out.println(res);
        }
    }
}

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

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

相关文章

certificate has expired错误解决

npm ERR! request to https://registry.npm.taobao.org/nodemon failed, reason: certificate has expired错误解决 npm在安装依赖包时出现以下错误。 作为最后的手段&#xff0c;你可以配置npm忽略SSL证书验证。这不是一个推荐的解决方案&#xff0c;因为它会降低安全性&…

window 镜像---负载篇

前提&#xff1a;需要修改window的powershell执行脚本的策略 步骤&#xff1a;以管理员身份打开powershell&#xff0c;执行 Get-ExecutionPolicy查看当前执行策略&#xff0c;若返回值是Restricted&#xff0c;需执行Set-ExecutionPolicy RemoteSigned powershell 版本信息&am…

计算机网络第6章(应用层)

6.1、应用层概述 我们在浏览器的地址中输入某个网站的域名后&#xff0c;就可以访问该网站的内容&#xff0c;这个就是万维网WWW应用&#xff0c;其相关的应用层协议为超文本传送协议HTTP 用户在浏览器地址栏中输入的是“见名知意”的域名&#xff0c;而TCP/IP的网际层使用IP地…

YouTrack 用户登录提示 JIRA 错误

就算输入正确的用户名和密码&#xff0c;我们也得到了下面的错误信息&#xff1a; youtrack Cannot retrieve JIRA user profile details. 解决办法 出现这个问题是因为 YouTrack 在当前的系统重有 JIRA 的导入关联。 需要把这个导入关联取消掉。 找到后台配置的导入关联&a…

【JMeter】使用技巧

在这此对新版本jmeter的学习温习的过程&#xff0c;发现了一些以前不知道的功能&#xff0c;所以&#xff0c;整理出来与大分享。本文内容如下。 如何使用英文界面的jmeter如何使用镜像服务器Jmeter分布式测试启动Debug 日志记录搜索功能线程之间传递变量 如何使用英文界面的…

SpringBoot实现统一异常处理

文章目录 前言实现步骤定义统一响应对象类定义业务异常枚举接口和实现定义业务异常基类定义全局异常处理切面测试和验证 总结 前言 近日心血来潮想做一个开源项目&#xff0c;目标是做一款可以适配多端、功能完备的模板工程&#xff0c;包含后台管理系统和前台系统&#xff0c…

Docker 搭建mysql 集群(二)

PXC方案 很明显 PXC方案在任何一个节点写入的数据都会同步到其他节点&#xff0c;数据双向同步的&#xff08;在任何节点上都可以同时读写&#xff09; 创建MySQL PXC集群 1 安装PXC镜像 docker pull percona/percona-xtradb-cluster:5.7.21 2 为PXC镜像改名 docker tag pe…

数据分析基础之《pandas(3)—DataFrame运算》

一、算术运算 1、add() 加法运算 2、sub() 减法运算 3、想要得到每天的涨跌幅大小&#xff0c;求出每天close-open价格差 # 算术运算 close data[close] open1 data[open] # 收盘价减去开盘价 data[m_price_change] close.sub(open1) data.head() 二、逻辑运算 1、逻辑…

Transformer实战-系列教程5:Vision Transformer 源码解读3

&#x1f6a9;&#x1f6a9;&#x1f6a9;Transformer实战-系列教程总目录 有任何问题欢迎在下面留言 本篇文章的代码运行界面均在Pycharm中进行 本篇文章配套的代码资源已经上传 6、Block类------构造函数 class Block(nn.Module):def __init__(self, config, vis):super(Blo…

【C++】类和对象(2)

这篇博客继续学习类和对象~&#xff0c;主要介绍了类的6个默认成员函数。 目录 类的6个默认成员函数 构造函数 概念 特性 析构函数 概念 特性 拷贝构造函数 特性 赋值运算符重载 运算符重载 赋值运算符重载 前置和后置重载 日期类的实现 const成员 取地址及cons…

FTP口令问题

FTP&#xff08;File Transfer Protocol &#xff0c;文件传输协议&#xff09;是一个文件传输协议&#xff0c;用户通 过FTP可从客户机程序向远程主机上传或下载文件&#xff0c;常用于网站代码维护、 日常 源码备份等。如果攻击者通过FTP匿名访问或者通过弱口令破解获取FTP…

Linux进程信号(2)--信号的保存

目录 1.阻塞信号 1.1 信号其他相关常见概念 1.实际执行信号的处理动作称为信号递达(Delivery&#xff09; 2.信号从产生到递达之间的状态,称为信号未决(Pending)。 3.进程可以选择阻塞 (Block )某个信号。 1.2信号在内核中的表示 sigset_t 信号集操作函数 使用sigprocm…

JAVA-File五个练习

下面习题思路大多都是&#xff1a; 1.获取路径下所有列表&#xff08;listfiles&#xff09;&#xff0c;2.遍历文件或文件夹&#xff08;增强for&#xff09;&#xff0c;3.判断是否是文件&#xff08;isFile&#xff09;并直接执行逻辑&#xff0c;4.判断当前是文件夹的情况&…

【React】redux状态管理、react-redux状态管理高级封装模块化

【React】react组件传参、redux状态管理 一、redux全局状态管理1、redux概述2、redux的组成1.1 State-状态1.2 Action-事件1.3 Reducer1.4 Store 3、redux入门案例1.1 前期准备1.2 构建store1.2.1 在src下新建store文件夹1.2.2 在store文件夹下新建index.ts文件1.2.3 在index.t…

Swift Vapor 教程(查询数据、插入数据)

上一篇简单写了 怎么创建 Swift Vapor 项目以及在开发过程中使用到的软件。 这一篇写一个怎么在创建的项目中创建一个简单的查询数据和插入数据。 注&#xff1a;数据库配置比较重要 先将本地的Docker启动起来&#xff0c;用Docker管理数据库 将项目自己创建的Todo相关的都删掉…

【python】python爱心代码【附源码】

一、实现效果&#xff1a; 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 二、完整代码&#xff1a; import math import random import threading import time from math import sin, cos, pi, log from tkinter import * import re# 烟花相关设置 Fireworks [] m…

STM32F407 CAN参数配置 500Kbps

本篇CAN参数适用 芯片型号&#xff1a;STM32F407xx系统时钟&#xff1a;168MHz&#xff0c;CAN挂载总线APB1为42M波 特 率 &#xff1a;500Kpbs引脚使用&#xff1a;TX_PB9&#xff0c;RX_PB8&#xff1b;修改为PA11PA12后&#xff0c;参数不变。 步骤一、打勾开启CAN&#xf…

vue使用es的reduce方法编译报错Error: Can‘t resolve ‘core-js/modules/es.array.reduce.js‘

哈喽 大家好啊 最近在vue使用es的reduce方法编译报错Error: Cant resolve core-js/modules/es.array.reduce.js 报错如图所示&#xff1a; 解决方案&#xff1a; npm install --save core-js 然后重新编译下将正常了 参考原文: 使用import异步加载语法报错_module not foun…

CAD-autolisp(四)——编译

目录 一、编译1.1 界面操作1.2 生成的应用程序&#xff08;二选一&#xff09; 二、后续学习 一、编译 编译&#xff1a;lsp后缀名为原文件&#xff0c;后缀名为fas、vlx为编译后文件&#xff0c;其会把sld、dcl、lsp等文件都编译进一个应用程序文件中加载&#xff1a;cad命令…

ZigBee学习——在官方例程基础实现点灯

IAR版本 :10.10.1 Z-stack版本 :3.0.2 文章目录 一、买的板子原理图二、实现过程2.1 重定义LED的物理映射(HAL层)2.2 创建LED事件(应用层)2.2.1 定义用户事件2.2.2 修改zclGenericApp_event_loop() 2.3 触发事件 一、买的板子原理图 二、实现过程 2.1 重定义LED的物理映射(HAL…
最新文章