浅说区间dp(下)

文章目录

  • 环形区间dp
  • 例题
  • [NOI1995] 石子合并
    • 题目描述
    • 输入格式
    • 输出格式
    • 样例 #1
      • 样例输入 #1
      • 样例输出 #1
    • 提示
    • 思路
  • [NOIP2006 提高组] 能量项链
    • 题目描述
    • 输入格式
    • 输出格式
    • 样例 #1
      • 样例输入 #1
      • 样例输出 #1
    • 提示
    • 思路
  • [NOIP2001 提高组] 数的划分
    • 题目描述
    • 输入格式
    • 输出格式
    • 样例 #1
      • 样例输入 #1
      • 样例输出 #1
    • 提示
    • 思路
  • 放苹果
    • 题目描述
    • 输入格式
    • 输出格式
    • 样例 #1
      • 样例输入 #1
      • 样例输出 #1
    • 样例 #2
      • 样例输入 #2
      • 样例输出 #2
    • 提示
    • 思路
  • 总结

环形区间dp

上一讲我们主要是讲解的链式的区间dp,但是我们经常会遇见一个环的dp问题,那么我们这时候应该怎么办呢,我们还是以一个生活例子来引入
又是wjq~~
wjq又要开始合并衣服了,最近的wjq中了邪,喜欢圆圆的东西,所以这一次她把衣服放成了一个圆圈,总计有 N 件衣服,每件衣服有一个遮挡程度,现要将衣服有次序地合并成一堆,规定每次只能选相邻的 2 件合并成新的一堆,并将新的一堆的遮挡程度,记为该次合并的得分。
首先我们不难想到,每一件衣服都有可能是起点,所以我们现在就有以下几种情况:

假设现在圆圈里有“黑丝”,“白丝”,“泳装”,“jk”
那么我们就有:
“黑丝”,“白丝”,“泳装”,“jk”
“白丝”,“泳装”,“jk”,“黑丝”
“泳装”,“jk”,“黑丝”,“白丝”
“泳装”,“jk”,“黑丝”,“白丝”
总计四种情况

如果我们去找起点的话,太过繁琐了,那么我们来想想怎么优化。不难发现,当我们求解“黑丝”,“白丝”,“泳装”,“jk”时,“白丝”,“泳装”,“jk”,已经有了答案,那么我们在计算“白丝”,“泳装”,“jk”,“黑丝”的时候,就不用再次计算“白丝”,“泳装”,“jk”了,所以我们这里可以将整个数组copy一遍,放到后面,这样我们就可以避免重复计算了
这样无论哪个点为起点,再向后面枚举3个点都是一个完整的区间,即区间[i,i+n-1]为一个完整的区间。环变链后再做一次和前面一样的dp,注意下范围和边界,最后因为所有的长度为n的区间都有可能是答案,所以答案在min(dp[i,i+n-1])中。
要注意i要枚举到n的后面,因为后面的dp会用到这些值
这一招叫做化环为链,长度翻倍,是区间dp问题中常见的处理手段


例题

[NOI1995] 石子合并

题目描述

在一个圆形操场的四周摆放 N N N 堆石子,现要将石子有次序地合并成一堆,规定每次只能选相邻的 2 2 2 堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。

试设计出一个算法,计算出将 N N N 堆石子合并成 1 1 1 堆的最小得分和最大得分。

输入格式

数据的第 1 1 1 行是正整数 N N N,表示有 N N N 堆石子。

2 2 2 行有 N N N 个整数,第 i i i 个整数 a i a_i ai 表示第 i i i 堆石子的个数。

输出格式

输出共 2 2 2 行,第 1 1 1 行为最小得分,第 2 2 2 行为最大得分。

样例 #1

样例输入 #1

4
4 5 9 4

样例输出 #1

43
54

提示

1 ≤ N ≤ 100 1\leq N\leq 100 1N100 0 ≤ a i ≤ 20 0\leq a_i\leq 20 0ai20

思路

这道题其实和上面的引入大同小异,可以直接套用

#include <iostream>
using namespace std;
const int N = 300;
const int INF = 10e9;
int n, dp[N][N], dp2[N][N];
int sum[N], s[N];int main(){cin >> n;for (int i = 1; i <= n; i++) {cin >> s[i];s[i + n] = s[i];}for(int i = 1; i <= n * 2; i++){sum[i] = s[i] + sum[i - 1];}for(int len = 1; len < n; len++){for (int i = 1; i <= (n * 2 - len); i++){int j = i + len;dp[i][j] = INF;for(int k = i; k < j; k++){dp[i][j] = min (dp[i][j], dp[i][k] + dp[k + 1][j] + sum[j] - sum[i - 1]);dp2[i][j] = max (dp2[i][j], dp2[i][k] + dp2[k + 1][j] + sum[j] - sum[i - 1]);}}}int ans = INF, ans2 = 0;for(int i = 1; i <= n; i++){ans = min(ans, dp[i][i + n - 1]);ans2 = max(ans2,dp2[i][i + n - 1]);}cout << ans << endl << ans2;
}

[NOIP2006 提高组] 能量项链

题目描述

在 Mars 星球上,每个 Mars 人都随身佩带着一串能量项链。在项链上有 N N N 颗能量珠。能量珠是一颗有头标记与尾标记的珠子,这些标记对应着某个正整数。并且,对于相邻的两颗珠子,前一颗珠子的尾标记一定等于后一颗珠子的头标记。因为只有这样,通过吸盘(吸盘是 Mars 人吸收能量的一种器官)的作用,这两颗珠子才能聚合成一颗珠子,同时释放出可以被吸盘吸收的能量。如果前一颗能量珠的头标记为 m m m,尾标记为 r r r,后一颗能量珠的头标记为 r r r,尾标记为 n n n,则聚合后释放的能量为 m × r × n m \times r \times n m×r×n(Mars 单位),新产生的珠子的头标记为 m m m,尾标记为 n n n

需要时,Mars 人就用吸盘夹住相邻的两颗珠子,通过聚合得到能量,直到项链上只剩下一颗珠子为止。显然,不同的聚合顺序得到的总能量是不同的,请你设计一个聚合顺序,使一串项链释放出的总能量最大。

例如:设 N = 4 N=4 N=4 4 4 4 颗珠子的头标记与尾标记依次为 ( 2 , 3 ) ( 3 , 5 ) ( 5 , 10 ) ( 10 , 2 ) (2,3)(3,5)(5,10)(10,2) (2,3)(3,5)(5,10)(10,2)。我们用记号 ⊕ \oplus 表示两颗珠子的聚合操作, ( j ⊕ k ) (j \oplus k) (jk) 表示第 j , k j,k j,k 两颗珠子聚合后所释放的能量。则第 4 4 4 1 1 1 两颗珠子聚合后释放的能量为:

( 4 ⊕ 1 ) = 10 × 2 × 3 = 60 (4 \oplus 1)=10 \times 2 \times 3=60 (41)=10×2×3=60

这一串项链可以得到最优值的一个聚合顺序所释放的总能量为:

( ( ( 4 ⊕ 1 ) ⊕ 2 ) ⊕ 3 ) = 10 × 2 × 3 + 10 × 3 × 5 + 10 × 5 × 10 = 710 (((4 \oplus 1) \oplus 2) \oplus 3)=10 \times 2 \times 3+10 \times 3 \times 5+10 \times 5 \times 10=710 (((41)2)3)=10×2×3+10×3×5+10×5×10=710

输入格式

第一行是一个正整数 N N N 4 ≤ N ≤ 100 4 \le N \le 100 4N100),表示项链上珠子的个数。第二行是 N N N 个用空格隔开的正整数,所有的数均不超过 1000 1000 1000。第 i i i 个数为第 i i i 颗珠子的头标记( 1 ≤ i ≤ N 1 \le i \le N 1iN),当 i < N i<N i<N 时,第 i i i 颗珠子的尾标记应该等于第 i + 1 i+1 i+1 颗珠子的头标记。第 N N N 颗珠子的尾标记应该等于第 1 1 1 颗珠子的头标记。

至于珠子的顺序,你可以这样确定:将项链放到桌面上,不要出现交叉,随意指定第一颗珠子,然后按顺时针方向确定其他珠子的顺序。

输出格式

一个正整数 E E E E ≤ 2.1 × 1 0 9 E\le 2.1 \times 10^9 E2.1×109),为一个最优聚合顺序所释放的总能量。

样例 #1

样例输入 #1

4
2 3 5 10

样例输出 #1

710

提示

NOIP 2006 提高组 第一题

思路

该题和合并石子(环)在处理方式上一样,都是通过把小区间合并成大区间,枚举合并两个区间的中间节点,计算出整个区间合并的最大能量因为也是一个环,所以我们还是先把环拆链,长度加倍,注意枚举顺序,因为是把小区间合并成大区间,所以先枚举区间长度,再枚举区间左端点,计算出区间右端点,最后再枚举最后一次合并的点,也就是断点,再计算答案。还是和前面一样,注意边界问题,区间长度不能大于n,也不能小于1.左右端点的范围不能小于或者大于真实情况。

#include <bits/stdc++.h>
using namespace std;const int MAX_N = 301;int dp[MAX_N][MAX_N];
int a[MAX_N];
int maxn=INT_MIN;int main() {int n;cin >> n;for (int i = 1; i <= n; ++i) {cin >> a[i];a[n+i]=a[i];}for (int len = 1; len <= 2*n; ++len) {for (int i = 1; i + len - 1 <= 2*n; ++i) {int j = i + len - 1;for (int k = i+1; k < j; ++k) {dp[i][j] = max(dp[i][j], dp[i][k] + dp[k][j] + a[i]*a[k]*a[j]);}}}for (int i=1;i<=n;i++){maxn=max(dp[i][i+n],maxn);}cout << maxn ;return 0;
}

[NOIP2001 提高组] 数的划分

题目描述

将整数 n n n 分成 k k k 份,且每份不能为空,任意两个方案不相同(不考虑顺序)。

例如: n = 7 n=7 n=7 k = 3 k=3 k=3,下面三种分法被认为是相同的。

1 , 1 , 5 1,1,5 1,1,5;
1 , 5 , 1 1,5,1 1,5,1;
5 , 1 , 1 5,1,1 5,1,1.

问有多少种不同的分法。

输入格式

n , k n,k n,k 6 < n ≤ 200 6<n \le 200 6<n200 2 ≤ k ≤ 6 2 \le k \le 6 2k6

输出格式

1 1 1 个整数,即不同的分法。

样例 #1

样例输入 #1

7 3

样例输出 #1

4

提示

四种分法为:
1 , 1 , 5 1,1,5 1,1,5;
1 , 2 , 4 1,2,4 1,2,4;
1 , 3 , 3 1,3,3 1,3,3;
2 , 2 , 3 2,2,3 2,2,3.

【题目来源】

NOIP 2001 提高组第二题

思路

首先因为这道题的数据范围比较小,所以我们可以直接打dfs,但是我们想象,如果N的范围比较大呢,自然,我们还是用动态规划
该题是一道相对比较复杂的区间DP,看上去和前面的区间DP类似,以每次划分作为阶段,枚举最后一次划分的位置k,那么求出所有dp[k][j-1]之和即为答案。这种解决办法是错误的,因为存在重复方案,为了避免重复,最后一次分的数量不能比前面少,但是这种做法没有考虑这个问题。
该题正确的做法是考虑分解方案中是否有一份中只有1个方案和没有一个的方案。如果有一个,那么答案相当于是dp[i-1][j-1],如果没有,那么每一份都减少一个1的方案也是合理的,即dp[i-j][j]。

#include<bits/stdc++.h>
using namespace std;int dp[2100][2100];
int main(){int n,k;cin>>n>>k;for (int i=1;i<=n;i++){dp[i][0]=1;dp[i][1]=1;}for (int x=2;x<=k;x++) {dp[1][x]=0;dp[0][x]=0;}for (int i=2;i<=n;i++){//i个数 for (int x=2;x<=k;x++){//每一个位置 if (i<=x)dp[i][x]=dp[i-1][x-1];else dp[i][x]=(dp[i-1][x-1]+dp[i-x][x]);}}cout<<dp[n][k];return 0;
}

放苹果

题目描述

m m m 个同样的苹果放在 n n n 个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法。( 5 , 1 , 1 5,1,1 5,1,1 1 , 1 , 5 1,1,5 1,1,5 是同一种方法)

输入格式

第一行是测试数据的数目 t t t,以下每行均包括二个整数 m m m n n n,以空格分开。

输出格式

对输入的每组数据 m m m n n n,用一行输出相应的结果。

样例 #1

样例输入 #1

1
7 3

样例输出 #1

8

样例 #2

样例输入 #2

3
3 2
4 3
2 7

样例输出 #2

2
4
2

提示

对于所有数据,保证: 1 ≤ m , n ≤ 10 1\leq m,n\leq 10 1m,n10 0 ≤ t ≤ 20 0 \leq t \leq 20 0t20

思路

同样的,这道题我们还是考虑动态规划。
该题和上一道题的解题思路一样,如果上一道题理解了,那么该题很容易想出状态转移方程。对于每一个盘子,最少放0个,如果存在放0个的盘子,答案为dp[i][j-1],如果不存在放0个的盘子,从每个盘子里面都拿掉一个,答案为 d p [ i − j ] [ j ] dp[i-j][j] dp[ij][j]
该题的难点不仅仅在于状态转移方程,还有初始状态。首先,i<j,上一道题为0,所以不用处理,但是该题当i<j时, d p [ i ] [ j ] = d p [ i ] [ i ] dp[i][j]=dp[i][i] dp[i][j]=dp[i][i],如果不单独处理那么状态转移中的 d p [ i − j ] [ j ] dp[i-j][j] dp[ij][j]就不存在,因为i-j为负数。
状态转移方程:
d p [ i ] [ j ] = d p [ i ] [ j − 1 ] + d p [ i − j ] [ j ] ; dp[i][j]=dp[i][j-1]+dp[i-j][j]; dp[i][j]=dp[i][j1]+dp[ij][j];当i,j都从1开始枚举时,需要用到 d p [ i ] [ 0 ] dp[i][0] dp[i][0],这到底算一算一种方案,我们也不太好确定,所以j最好从2开始枚举,这样我们需要初始化 d p [ i ] [ 1 ] dp[i][1] dp[i][1]的值,很明显 d p [ i ] [ 1 ] = 1 dp[i][1]=1 dp[i][1]=1
还需要用到 d p [ i − j ] [ j ] dp[i-j][j] dp[ij][j]的值,我们先判断i,j的大小,此时i>=j,我们会用到 d p [ 0 ] [ j ] dp[0][j] dp[0][j]的值,我们还需要初始化 d p [ 0 ] [ j ] dp[0][j] dp[0][j]的值,很明显也为1。

#include<bits/stdc++.h>
using namespace std;int dp[2100][2100];
int main(){int n,k,t;cin>>t;while (t--){memset(dp,0,sizeof(dp));cin>>n>>k;for (int i=1;i<=n;i++){dp[i][0]=1;dp[i][1]=1;}for (int i=1;i<=k;i++){dp[0][i]=1;dp[1][i]=1;}for (int i=2;i<=n;i++){//i个数 for (int x=2;x<=k;x++){//每一个位置 if (i<x)dp[i][x]=dp[i][i];else dp[i][x]=(dp[i][x-1]+dp[i-x][x])%1000007;}}cout<<dp[n][k]<<endl;;}return 0;
}

总结

好了,到目前为止,普及组所要用到的动态规划问题我们基本上是讲完了,不知道大家有没有收获呢?如果有问题,欢迎到评论区留言,或者私信博主,如果喜欢博主的博客的话,请点一个赞,蟹蟹~~

请添加图片描述

请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述

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

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

相关文章

你也许不知道,自己可能是一个「热人」

稍微标题党了一下。: ) 今天想跟大家分享的&#xff0c;是一种很少有人了解的人格特质。它非常普遍&#xff0c;许多人都或多或少有一些倾向&#xff0c;但却很少有人意识到它。 不妨看一看&#xff0c;你有没有下面这些特征&#xff1a; 有着极其旺盛的求知欲&#xff0c;对许…

paddleocr icdar2015数据集训练dbnet检测模型

参考&#xff1a;https://github.com/PaddlePaddle/PaddleOCR/blob/main/doc/doc_ch/detection.md 原理 DBNET论文 Real-time Scene Text Detection with Differentiable Binarization 参考&#xff1a;https://blog.csdn.net/qq_35756383/article/details/118679258 Real-T…

【STC89C51单片机】定时器/计数器的理解

目录 定时器/计数器1. 定时器怎么定时简单理解&#xff08;加1经过了多少时间&#xff09;什么是时钟周期什么是机器周期 2.如何设置定时基本结构相关寄存器1. TMOD寄存器2. TCON寄存器 代码示例 定时器/计数器 STC89C51单片机的定时器和计数器&#xff08;Timers and Counter…

【BUG】已解决:NameError: name ‘XXX‘ is not defined

已解决&#xff1a;NameError: name ‘XXX‘ is not defined 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#xff0c;我是博主英杰&#xff0c;211科班出身&#xff0c;就职于医疗科技公司&#xff0c;热衷分享知识&#xff0c;武汉城市开发者社…

Harmony 状态管理 @Local 和 @Param

Harmony 状态管理 Local 和 Param Local 背景 Local 是harmony应用开发中的v2版本中 对标**State**的状态管理修饰器&#xff0c;它解决了 State 对状态变量更改的检测混乱的问题&#xff1a; State 修饰的状态变量 可以是组件内部自己定义的State 修饰的状态 也可以由外部父…

路径规划 | 基于DQN深度强化学习算法的路径规划(Matlab)

目录 效果一览基本介绍程序设计参考文献 效果一览 基本介绍 DQN路径规划算法 基于深度强化学习算法的路径规划 matlab2023b 栅格环境&#xff0c;走迷宫&#xff0c;可以通过窗口界面方便观察交互过程&#xff0c;代码注释详尽。 程序设计 完整源码和数据私信博主回复基于DQN深…

Vue学习---vue cli 项目创建

使用的编辑工具webStorm 创建例子: hello vue create hello 选择 vue3 进行创建 运行 npm run serve 测试访问&#xff1a;http://localhost:8080 改动内容重新编译&#xff1a; npm run build dist 目录就是编译后的可运行内容

1分钟带你了解苹果手机删除照片恢复全过程

在日常使用苹果手机时&#xff0c;我们可能会不小心删除掉一些重要的照片&#xff0c;这让人非常烦恼。那么苹果手机怎么恢复删除的照片&#xff1f;下面小编将会向大家介绍苹果手机恢复删除的照片的方法&#xff0c;帮助大家轻松找回你丢失的照片。 一、利用“最近删除”文件夹…

甲骨文面试题【动态规划】力扣377.组合总和IV

给你一个由 不同 整数组成的数组 nums &#xff0c;和一个目标整数 target 。请你从 nums 中找出并返回总和为 target 的元素组合的个数。 题目数据保证答案符合 32 位整数范围。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,3], target 4 输出&#xff1a;7 解释&#x…

【Linux】详解加锁实现线程互斥

一、多线程不加线程互斥可能会引发的问题 下面是一个抢标逻辑。抢票为什么会抢到负数&#xff1a;假设当票数为1时&#xff0c;此时四个进程的判断条件tickets都大于0&#xff0c;都会进入抢票操作&#xff0c;第一个进程抢完票以后tickets0并写回内存&#xff0c;第二个进程再…

Xcode进行真机测试时总是断连,如何解决?

嗨。大家好&#xff0c;我是兰若姐姐。最近我在用真机进行app自动化测试的时候&#xff0c;经常会遇到xcode和手机断连&#xff0c;每次断连之后需要重新连接&#xff0c;每次断开都会出现以下截图的报错 当这种情况出现时&#xff0c;之前执行的用例就相当于白执行了&#xff…

Adobe XD中文设置指南:专业设计师的现场解答

Adobe XD是世界领先的在线合作UI设计工具。它摆脱了Sketch、Figma等传统设计软件对设备的依赖&#xff0c;使设计师可以随时随地使用任何设备打开网页浏览器&#xff0c;轻松实现跨平台、跨时空的设计合作。然后&#xff0c;为了提高国内设计师的使用体验&#xff0c;Adobe XD如…

爬虫(二)——爬虫的伪装

前言 本文是爬虫系列的第二篇文章&#xff0c;主要讲解关于爬虫的简单伪装&#xff0c;以及如何爬取B站的视频。建议先看完上一篇文章&#xff0c;再来看这一篇文章。要注意的是&#xff0c;本文介绍的方法只能爬取免费视频&#xff0c;会员视频是无法爬取的哦。 爬虫的伪装 …

C++类与对象(补)

感谢大佬的光临各位&#xff0c;希望和大家一起进步&#xff0c;望得到你的三连&#xff0c;互三支持&#xff0c;一起进步 个人主页&#xff1a;LaNzikinh-CSDN博客 文章目录 前言一.默认成员函数二.static三.友元四.匿名对象总结 前言 类的默认成员函数&#xff0c;默认成员…

linux centos limits.conf 修改错误,无法登陆问题修复 centos7.9

一、问题描述 由于修改/etc/security/limits.conf这个文件中的值不当&#xff0c;重启后会导致其账户无法远程登录&#xff0c;本机登录。 如改成这样《错误示范》&#xff1a; 会出现&#xff1a; 二、解决 现在知道是由于修改limits.conf文件不当造成的&#xff0c;那么就…

Android-- 集成谷歌地图

引言 项目需求需要在谷歌地图&#xff1a; 地图展示&#xff0c;设备点聚合&#xff0c;设备站点&#xff0c;绘制点和区域等功能。 我只针对我涉及到的技术做一下总结&#xff0c;希望能帮到开始接触谷歌地图的伙伴们。 集成步骤 1、在项目的modle的build.gradle中添加依赖如…

p19 C语言操作符详解

算术操作符 1.除了%操作符之外&#xff0c;其他的几个操作符可以作用于整数和浮点数。 2.对于/操作符如果两个操作数都为整数&#xff0c;执行整数除法。而只要有浮点数值型的就是浮点除法。 3.%操作符的两个操作数必须为 整数。返回的是整除之后的余数。 #include<std…

计算机毕业设计-基于Springboot的养老院管理系统-源码程序文档

项目源码&#xff0c;请关注❥点赞收藏并私信博主&#xff0c;谢谢~ 本系统开发采用技术为JSP、Bootstrap、Ajax、SSM、Java、Tomcat、Maven 此文章为本人亲自指导加编写&#xff0c;禁止任何人抄袭以及各类盈利性传播&#xff0c; 相关的代码部署论文ppt代码讲解答辩指导文件…

SpringBoot以及swagger的基本使用

1、SpringBoot是什么&#xff1f; 一种快速开发、启动Spring的框架、脚手架 遵循“约定优于配置”的思想&#xff0c;使得能够快速创建和配置Spring应用 2、SpringBoot的核心特性 自动配置&#xff0c;一些依赖、默认配置都预设好了&#xff0c;减少了配置量起步依赖&#x…

表格竖向展示

最近在做手机端web页面&#xff0c;页面中需要有个表格来显示数据&#xff0c;但是由于数据太多页面太窄&#xff0c;table展示横向滑动的话感觉很丑。所以让表格竖向显示了 具体页面如下: 实现代码&#xff1a;当然代码里面绑定的数据啊什么的你都可以修改为自己的内容&#…