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 ...
随机推荐
- 金蝶云星空与吉客云电商ERP数据对接
01 系统说明: 吉客云 吉客云: 从业务数字化和组织数字化两个方向出发,以生成流程的闭环为依归,致力于为企业的数字化升级提供落地工具.销售订单层面,吉客云对接了国内外主流的销售平台,兼容了电商渠道. ...
- [Codechef REBXOR]Nikitosh and xor (Trie,异或)
题目传送门 分析:首次考虑暴力枚举 \(l_{1},r_{1},l_{2},r_{2}\),配合前缀和时间复杂度 \(O(N^{4})\),需要想办法优化.对于这种两段区间不重合的,我们考虑枚举两段区 ...
- centos虚拟机安装
目录 一.准备工作 1.vmware workstation软件安装 2.准备ios镜像 二.创建Centos虚拟机 三.进行Centos7的系统安装 四.虚拟机快照的使用 1.创建虚拟机快照 2.还 ...
- [Python急救站]火车购票程序
火车购票程序 如果要一直执行程序,加个while循环即可.要是要智能判断月份,可以通过调取当前时间进行判断即可. print(""" 1.每年的1-3月和7-9月凭学生证 ...
- 基于 Webpack5 Module Federation 的业务解耦实践
我们是袋鼠云数栈 UED 团队,致力于打造优秀的一站式数据中台产品.我们始终保持工匠精神,探索前端道路,为社区积累并传播经验价值. 本文作者:贝儿 前言 本文中会提到很多目前数栈中使用的特定名词,统一 ...
- .NET周刊 【12月第3期 2023-12-24】
国内文章 CAP 8.0 版本发布通告 - CAP 7岁生日快乐! https://www.cnblogs.com/savorboard/p/cap-8-0.html 今天宣布CAP 8.0版本正式发 ...
- kubernetes不同pod之间调用(四)
kubernetes不同pod之间调用(四) k8s系列 源自我工作上的实际场景,记录于此. kubernetes不同服务间的调用.kubernetes不同容器间的调用.kubernetes不同- 今 ...
- Zookeeper 的基本使用
维基百科对 Zookeeper 的介绍如下所示: Apache ZooKeeper是 Apache 软件基金会的一个软件项目,它为大型分布式计算提供开源的分布式配置服务.同步服务和命名注册 ZooKe ...
- Java 并发编程(七)线程池
任务的创建与执行 在多线程的编程环境中,理想的情况是每个任务之间都存在理想的边界,各个任务之间相互独立,这样才能够享受到并发带来的明显的性能提升,并且,由于每个任务之间如果都是独立的,对于并发的处理也 ...
- 文心一言 VS 讯飞星火 VS chatgpt (39)-- 算法导论5.4 3题
三.在生日悖论的分析中,要求各人生日彼此独立是否很重要?或者,是否只要两两成对独立就足够了?证明你的答案. 文心一言: 在生日悖论的分析中,要求各人生日彼此独立是非常重要的.这是因为,如果各人生日不是 ...