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. 🔥🔥Java开发者的Python快速实战指南:探索向量数据库之文本搜索

    前言 如果说Python是跟随我的步伐学习的话,我觉得我在日常开发方面已经没有太大的问题了.然而,由于我没有Python开发经验,我思考着应该写些什么内容.我回想起学习Java时的学习路线,直接操作数 ...

  2. 在net中通过Autofac实现AOP的方法及实例详解

    在本示例中,我们将使用Autofac和AspectC(Autofac.Extras.DynamicProxy2)来演示如何实现AOP(面向切面编程).我们将创建一个简单的C#控制台应用程序,并应用AO ...

  3. 【译】Visual Studio 17.8 中我最喜欢的特性

    对于 Visual Studio 团队来说,这是忙碌的一周,他们准备了 Ignite 和 .NET Conf,并发布了最新版本的 Visual Studio 2022,即17.8版本.有很多很酷的新功 ...

  4. 常用API之IP定位地区

    常用API之IP定位地区 高德地图API https://lbs.amap.com/api/webservice/guide/api/ipconfig 百度地图API https://lbsyun.b ...

  5. 文心一言 VS 讯飞星火 VS chatgpt (42)-- 算法导论5.4 6题

    六.假设将n个球投人 n 个箱子里,其中每次投球独立,并且每个球等可能落入任何箱子.空箱子的数目期望是多少?正好有一个球的箱子的数目期望是多少? 文心一言: 这是一个典型的概率问题.首先,我们可以通过 ...

  6. 【一行代码秒上云】Serverless六步构建全栈网站

    摘要:Serverless怎么玩?听一千道一万不如亲手来实践,跟着我们以华为云Serverless实践FunctionGraph来免费体验一下六步构建全栈网站吧 前言: Serverless怎么玩?听 ...

  7. 想学AI开发很简单:只要你会复制粘贴

    摘要:本次实践基于 mobilenetV2 实现猫狗图像分类,贯穿了数据集获取及处理.预训练模型微调及迁移.端侧部署及推理等环节和知识点,体会到了 MindSpore 简单的开发体验和全场景快速部署的 ...

  8. Python 没有函数重载?如何用装饰器实现函数重载?

    摘要:Python 不支持函数重载.当我们定义了多个同名的函数时,后面的函数总是会覆盖前面的函数,因此,在一个命名空间中,每个函数名仅会有一个登记项(entry). 本文分享自华为云社区<为什么 ...

  9. 云图说|Git云上仓库哪家好?一张图了解华为云代码托管服务

    阅识风云是华为云信息大咖,擅长将复杂信息多元化呈现,其出品的一张图(云图说).深入浅出的博文(云小课)或短视频(云视厅)总有一款能让您快速上手华为云.更多精彩内容请单击此处. 摘要: 云办公时代已然到 ...

  10. 火出边际的Serverless,你居然还不了解?

    摘要:图灵奖获得者David A. Patterson和Spark共同创始人Ion Stoica,在19年伯克利的会议上发布Serverless将是下一代默认的计算范式. 本文分享自华为云社区< ...