0x53 动态规划-区间DP
A: 石子合并
所求问题:1到n这些石子合并最少需要多少代价
由于石子合并的顺序可以任意,我们将石子分为两个部分
子问题:1到k这堆石子合并,k+1到n这堆石子合并,再把两堆石子合并,需要多少代价\((1<=k<=n)\)
那么便可以得到状态转移方程 $$dp[i][j]=min(dp[i][k]+dp[k+1][j]+……)$$
i到j这些石子合并,代价不仅仅是分开的两堆内部合并的代价,还有两堆石子相互合并的所带来的代价消耗,可得出省略号中的答案为a[i]+a[i+1]+……+a[j]
为了加快效率,我们设立一个sum数组来记录前缀和,那么可得到完整的状态转移方程:
\(dp[i][j]=min(dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1])\)
需要注意的是,由于dp求最小值,需要将dp预处理为无穷大
#include<bits/stdc++.h>
using namespace std;
const int N = 310;
int a[N], n;
int dp[N][N], sum[N];
int main() {
//freopen("in.txt", "r", stdin);
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> n;
memset(dp, 0x3f, sizeof dp);
for (int i = 1; i <= n; ++i)cin >> a[i], dp[i][i] = 0, sum[i] = sum[i - 1] + a[i];
//F[l,r] = min(F[l,k],F[k + 1.r] + sum[l,r]
for (int len = 1; len < n; len++)
for (int i = 1; i <= n - len; i++){
int j = i + len;
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]);
}
cout << dp[1][n] << endl;
}
B: Polygon
题目描述
Polygon is a game for one player that starts on a polygon with N vertices, like the one in Figure 1, where N=4. Each vertex is labelled with an integer and each edge is labelled with either the symbol + (addition) or the symbol * (product). The edges are numbered from 1 to N.

On the first move, one of the edges is removed. Subsequent moves involve the following steps:
- pick an edge E and the two vertices V1 and V2 that are linked by E; and
- replace them by a new vertex, labelled with the result of performing the operation indicated in E on the labels of V1 and V2.
The game ends when there are no more edges, and its score is the label of the single vertex remaining.
Consider the polygon of Figure 1. The player started by removing edge 3. After that, the player picked edge 1, then edge 4, and, finally, edge 2. The score is 0.

Write a program that, given a polygon, computes the highest possible score and lists all the edges that, if removed on the first move, can lead to a game with that score.
输入描述:
Your program is to read from standard input. The input describes a polygon with N vertices. It contains two lines. On the first line is the number N. The second line contains the labels of edges 1, ..., N, interleaved with the vertices' labels (first that of the vertex between edges 1 and 2, then that of the vertex between edges 2 and 3, and so on, until that of the vertex between edges N and 1), all separated by one space. An edge label is either the letter t (representing +) or the letter x (representing *).
$3 <= N <= 50 $
For any sequence of moves, vertex labels are in the range \([-32768,32767]\).
输出描述:
Your program is to write to standard output. On the first line your program must write the highest score one can get for the input polygon. On the second line it must write the list of all edges that, if removed on the first move, can lead to a game with that score. Edges must be written in increasing order, separated by one space.
输入
4
t -7 t 4 x 2 x 5
输出
33
1 2
解题思路
这道题的题意大致是对于n个点的环先删除一个点后,根据连线的运算符逐渐合并各个点,最后求最大的结果可能是多少。一道经典的区间DP题,有几个点需要注意一下:
- 需要枚举最开始删除的是哪条边
- 由于一开始是个环,删边后可能从中间断开,导致区间不连续,无法使用区间DP。解决方法是将原始数组复制一倍,这样就能保证能够使用区间DP。
- 由于元素可能存在负值,负负相乘得正后可能得到的结果更大。所以在维护结果的时候,既要维护最大值,也要维护最小值。
#include<bits/stdc++.h>
using namespace std;
const int N = 106, INF = 0x3f3f3f3f;
char c[N];
int a[N], dp_max[N][N], dp_min[N][N];
int main() {
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> c[i];
cin >> a[i];
}
for (int i = n + 1; i <= (n << 1); i++) {
c[i] = c[i - n];
a[i] = a[i - n];
}
memset(dp_max, 0xcf, sizeof(dp_max));
memset(dp_min, 0x3f, sizeof(dp_min));
for (int i = 1; i <= (n << 1); i++) dp_max[i][i] = dp_min[i][i] = a[i];
for (int len = 2; len <= n; len++)
for (int l = 1; l + len - 1 <= (n << 1); l++) {
int r = l + len - 1;
for (int k = l + 1; k <= r; k++)
if (c[k] == 't') {
dp_max[l][r] = max(dp_max[l][r], dp_max[l][k - 1] + dp_max[k][r]);
dp_min[l][r] = min(dp_min[l][r], dp_min[l][k - 1] + dp_min[k][r]);
}
else {
dp_max[l][r] = max(dp_max[l][r], max(dp_max[l][k - 1] * dp_max[k][r], dp_min[l][k - 1] * dp_min[k][r]));
dp_min[l][r] = min(dp_min[l][r], min(dp_max[l][k - 1] * dp_max[k][r], min(dp_min[l][k - 1] * dp_min[k][r], min(dp_max[l][k - 1] * dp_min[k][r], dp_min[l][k - 1] * dp_max[k][r]))));
}
}
int ans = -INF;
for (int i = 1; i <= n; i++) ans = max(ans, dp_max[i][i + n - 1]);
cout << ans << endl;
for (int i = 1; i <= n; i++)
if (ans == dp_max[i][i + n - 1])
cout << i << " ";
return 0;
}
C:金字塔
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9;
ll f[310][310];
string s;
ll dfs(int l, int r) {
if (l > r) return 0;//递归边界
if (l == r) return 1;//递归边界
if (f[l][r] != -1) return f[l][r];//记忆化
if (s[l] != s[r]) return 0;
f[l][r] = 0;
for (int k = l + 2; k <= r; k++)
(f[l][r] += dfs(l + 1, k - 1) * dfs(k, r)) %= mod;
return f[l][r];
}
int main() {
//freopen("in.txt", "r", stdin);
memset(f, -1, sizeof f);//-1代表没有计算过
cin >> s;
cout << dfs(0, s.length() - 1) << endl;
}
0x53 动态规划-区间DP的更多相关文章
- 动态规划——区间dp
在利用动态规划解决的一些实际问题当中,一类是基于区间上进行的,总的来说,这种区间dp是属于线性dp的一种.但是我们为了更好的分类,这里仍将其单独拿出进行分析讨论. 让我们结合一个题目开始对区间dp的探 ...
- 动态规划——区间DP,计数类DP,数位统计DP
本博客部分内容参考:<算法竞赛进阶指南> 一.区间DP 划重点: 以前所学过的线性DP一般从初始状态开始,沿着阶段的扩张向某个方向递推,直至计算出目标状态. 区间DP也属于线性DP的一种, ...
- 模板 - 动态规划 - 区间dp
因为昨天在Codeforces上设计的区间dp错了(错过了上紫的机会),觉得很难受.看看学长好像也有学,就不用看别的神犇的了. 区间dp处理环的时候可以把序列延长一倍. 下面是 $O(n^3)$ 的朴 ...
- 动态规划---区间dp
今天写内网题,连着写了两道区间dp,这里就总结一下. 区间dp思想主要是先枚举f[i][j]中的i,再枚举j,再枚举一个1~j之间的变量k,一般是f[i][j] = max(f[i][j],f[i][ ...
- [hdu contest 2019-07-29] Azshara's deep sea 计算几何 动态规划 区间dp 凸包 graham扫描法
今天hdu的比赛的第一题,凸包+区间dp. 给出n个点m个圆,n<400,m<100,要求找出凸包然后给凸包上的点连线,连线的两个点不能(在凸包上)相邻,连线不能与圆相交或相切,连线不能相 ...
- Hdu OJ 5115 Dire Wolf (2014ACM/ICPC亚洲区北京站) (动态规划-区间dp)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5115 题目大意:前面有n头狼并列排成一排, 每一头狼都有两个属性--基础攻击力和buff加成, 每一头 ...
- Light OJ 1025 - The Specials Menu(动态规划-区间dp)
题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1025 题目大意:一串字符, 通过删除其中一些字符, 能够使这串字符变成回文串. ...
- [SCOI2007]压缩(动态规划,区间dp,字符串哈希)
[SCOI2007]压缩 状态:设\(dp[i][j]\)表示前i个字符,最后一个\(M\)放置在\(j\)位置之后的最短字串长度. 转移有三类,用刷表法来实现. 第一种是直接往压缩串后面填字符,这样 ...
- [jdoj1090]矩阵_区间dp
矩阵 jdoj-1910 题目大意:给你连续的n个矩阵的长和宽,保证每连续的两个相邻矩阵满足相乘的条件,不能改变题目中矩阵的位置,求将这些矩阵相乘为一个矩阵的最小乘法次数. 注释:1<=n< ...
- 动态规划(区间DP):HDU 5115 Dire Wolf
Dire wolves, also known as Dark wolves, are extraordinarily large and powerful wolves. Many, if not ...
随机推荐
- 【Javaweb】servlet一
什么是servlet 1.servlet是JavaEE规范之一,规范就是接口. 2.servlet是Javaweb三大组件之一.三大组件分别是:servlet程序.filter过滤器.listener ...
- java String字符串总结
这里我们将总结字符串相关的知识,除了总结String的API用法,同时我们还会总结一些相关的知识点,包括字符串常量池.StringBuffer.StringBuilder,以及equals和==的用法 ...
- Qt官网开源最新版下载安装保姆级教程
什么是Qt(了解请跳过) Qt 基本介绍 Qt 是一个跨平台C++图形用户界面应用程序开发框架. 有关 Qt 的详细介绍,可以参考这篇文章: Qt是什么?Qt简介(非常全面) - 李清龙的文章 - 知 ...
- 开发必备工具、插件【ME】
工欲善其事,必先利其器,记录自己开发中常用的工具.插件: 慢慢更新... 一.必备 1.Visual Studio.IntelliJ IDEA .Sublime Text 3 2.TeamViewe ...
- 【WCH以太网接口系列芯片】基于CH395的组播请求(IGMP)
在上一篇文章中,我们通过直连电脑测试了CH395在组播环境中进行数据的收发,但在实际的使用场景中更多的是将CH395接入局域网环境中.因此,我们需要使用到一个协议--IGMP(Internet Gro ...
- 国产 Web 组态软件在玻璃生产线中的应用
概述 随着工厂信息化.数字化发展,智慧生产车间成为必然发展趋势,通过智能硬件.物联网.大数据等智慧化技术与手段,提高车间生产设备.工艺设备的智能执行能力,从而提升整个车间乃至工厂的智能化.网络化 ...
- Kernel Memory 入门系列:生成并获取文档摘要
Kernel Memory 入门系列:生成并获取文档摘要 前面在RAG和文档预处理的流程中,我们得到一个解决方案,可以让用户直接获取最终的问题答案. 但是实际的业务场景中,仍然存在一些基础的场景,不需 ...
- loader编写小记
此项目在一些大佬的基础上进行了修改,或许能提供一些思路.还在学习中很菜很菜,不足之处还请师傅们多多指点 tips 对shellcode使用AES + Base85加密后以txt保存在远端供下载. 针对 ...
- 劫持 PE 文件:新建节表并插入指定 DLL 文件
PE格式简介 PE(Portable Executable)格式,是微软Win32环境可移植可执行文件(如exe.dll.vxd.sys和vdm等)的标准文件格式.PE格式衍生于早期建立在VAX(R) ...
- 【.NET开发福音】使用Visual Studio将JSON格式数据自动转化为对应的类
前言: 这段时间一直在做一个第三方平台的对接,对接第三方其实无非就是请求调用第三方的相关接口接收返回过来的相关参数.因此在这个过程中就会涉及大量的JSON响应参数或者请求参数转化为对应的实体类的情况, ...