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:

  1. pick an edge E and the two vertices V1 and V2 that are linked by E; and
  2. 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题,有几个点需要注意一下:

  1. 需要枚举最开始删除的是哪条边
  2. 由于一开始是个环,删边后可能从中间断开,导致区间不连续,无法使用区间DP。解决方法是将原始数组复制一倍,这样就能保证能够使用区间DP。
  3. 由于元素可能存在负值,负负相乘得正后可能得到的结果更大。所以在维护结果的时候,既要维护最大值,也要维护最小值。
#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的更多相关文章

  1. 动态规划——区间dp

    在利用动态规划解决的一些实际问题当中,一类是基于区间上进行的,总的来说,这种区间dp是属于线性dp的一种.但是我们为了更好的分类,这里仍将其单独拿出进行分析讨论. 让我们结合一个题目开始对区间dp的探 ...

  2. 动态规划——区间DP,计数类DP,数位统计DP

    本博客部分内容参考:<算法竞赛进阶指南> 一.区间DP 划重点: 以前所学过的线性DP一般从初始状态开始,沿着阶段的扩张向某个方向递推,直至计算出目标状态. 区间DP也属于线性DP的一种, ...

  3. 模板 - 动态规划 - 区间dp

    因为昨天在Codeforces上设计的区间dp错了(错过了上紫的机会),觉得很难受.看看学长好像也有学,就不用看别的神犇的了. 区间dp处理环的时候可以把序列延长一倍. 下面是 $O(n^3)$ 的朴 ...

  4. 动态规划---区间dp

    今天写内网题,连着写了两道区间dp,这里就总结一下. 区间dp思想主要是先枚举f[i][j]中的i,再枚举j,再枚举一个1~j之间的变量k,一般是f[i][j] = max(f[i][j],f[i][ ...

  5. [hdu contest 2019-07-29] Azshara's deep sea 计算几何 动态规划 区间dp 凸包 graham扫描法

    今天hdu的比赛的第一题,凸包+区间dp. 给出n个点m个圆,n<400,m<100,要求找出凸包然后给凸包上的点连线,连线的两个点不能(在凸包上)相邻,连线不能与圆相交或相切,连线不能相 ...

  6. Hdu OJ 5115 Dire Wolf (2014ACM/ICPC亚洲区北京站) (动态规划-区间dp)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5115 题目大意:前面有n头狼并列排成一排, 每一头狼都有两个属性--基础攻击力和buff加成, 每一头 ...

  7. Light OJ 1025 - The Specials Menu(动态规划-区间dp)

    题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1025 题目大意:一串字符, 通过删除其中一些字符, 能够使这串字符变成回文串. ...

  8. [SCOI2007]压缩(动态规划,区间dp,字符串哈希)

    [SCOI2007]压缩 状态:设\(dp[i][j]\)表示前i个字符,最后一个\(M\)放置在\(j\)位置之后的最短字串长度. 转移有三类,用刷表法来实现. 第一种是直接往压缩串后面填字符,这样 ...

  9. [jdoj1090]矩阵_区间dp

    矩阵 jdoj-1910 题目大意:给你连续的n个矩阵的长和宽,保证每连续的两个相邻矩阵满足相乘的条件,不能改变题目中矩阵的位置,求将这些矩阵相乘为一个矩阵的最小乘法次数. 注释:1<=n< ...

  10. 动态规划(区间DP):HDU 5115 Dire Wolf

    Dire wolves, also known as Dark wolves, are extraordinarily large and powerful wolves. Many, if not ...

随机推荐

  1. 一个基于.NET Core开源、跨平台的仓储管理系统

    前言 今天给大家推荐一个基于.NET Core开源.跨平台的仓储管理系统,数据库支持MSSQL/MySQL:ZEQP.WMS. 仓储管理系统介绍 仓储管理系统(Warehouse Management ...

  2. PLC 和Modbus/串口设备现场总线通信及短信报警解决方案

    在实现 Modbus 设备与 PROFIBUS DP 协议 PLC 通讯的同时可以在手机端实时的接收报警短信,使客户足不出户了解设备与 PLC 的状态,及时处理现场中的问题. 系统组成 Modbus ...

  3. 介绍一个我开源的项目:一键部署 VictoriaMetrics 群集

    作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢! cnblogs博客 zhihu Github 公众号:一本正经的瞎扯 我实在是非常喜欢这个强大的 metrics 监控组件 Vi ...

  4. 每天5分钟复习OpenStack(十二)Ceph FileStore 和 BlueSotre

    一个最小化的Ceph集群需要三个组件MON MGR OSD.上一章我们部署了MON,本章节我们完成剩下MGR 和OSD 的部署.在文末我们将重点介绍下什么是FileStore和BlueStore,并详 ...

  5. SSPRQ码型设计

    serdes速率超过50G之后,在VSR光模块场景下SSPRQ使用较为广泛.SSPRQ用于PAM4光模块眼图压力,闭合率测试. 但是有很多serdes IP不支持此功能.出于测试需要需要新设计SSPR ...

  6. [GDOI22pj2C] 教室的电子钟

    第三题 教室的电子钟 提交文件: clock.cpp 输入文件: clock.in 输出文件: clock.out 时间空间限制: 1 秒, 256 MB 为了迎接 GDOI,小蒟蒻学校所有教室的钟都 ...

  7. 同样的SQL,怎么突然就慢了?

    本篇文章素材来源于某银行系统的一次性能问题分析. 许久没写这种troubleshooting类型的技术文章了,因为曾在服务公司呆过多年,工作原因,这方面之前做的多,听的更多,导致已经达到在自己认知维度 ...

  8. ASP.NET Core 8 的内存占用可以更低吗?

    Maoni Stephens 是 .NET 垃圾回收器 (GC) 的首席架构师之一,她在2023年8月份发表了一篇关于 .NET GC 新功能的博客文章,该功能称为 Dynamic Adaption ...

  9. libgdx摄像头的移动

    要知道,做一个游戏,摄像头是必不可少的.接下来,我将讲解libgdx里面摄像头的移动 2d摄像头OrthographicCamera也叫做正交相机 结果展示: 按上下左右是可以移动的 Orthogra ...

  10. MinIO客户端之rb

    MinIO提供了一个命令行程序mc用于协助用户完成日常的维护.管理类工作. 官方资料 mc rb 彻底删除指定的桶. 命令如下: ./mc rb local1/bkt1 控制台的输出,如下: mc: ...