动态规划自古以来是DALAO凌虐萌新的分水岭,但有些OIer认为并没有这么重要——会打暴力,大不了记忆化。但是其实,动态规划学得好不好,可以彰显出一个OIerOIer的基本素养——能否富有逻辑地思考一些问题,以及更重要的——能否将数学、算筹学(决策学)、数据结构合并成一个整体并且将其合理运用qwqqwq

  而我们首先要了解的,便是综合难度在所有动规题里最为简单的线性动规了。线性动规既是一切动规的基础,同时也可以广泛解决生活中的各项问题——比如在我们所在的三维世界里,四维的时间就是不可逆式线性,比如我们需要决策在相同的时间内做价值尽量大的事情,该如何决策,最优解是什么——这就引出了动态规划的真正含义:

      在一个困难的嵌套决策链中,决策出最优解。

2022百度之星程序设计大赛 正式开启!
24万奖金池、大赛纪念T恤、招聘绿色通道,已为你准备就绪

赛题介绍:使用C,C++,Python及Java等程序设计语言编写程序,解决规定数量的问题。重点考察选手的基础算法和程序设计能力。

【不收报名费】
大赛官网:star.baidu.com
报名截止日期:2022年9月4日
官方Q群:883113756、1040538181
报名流程:https://docs.qq.com/doc/DVkRpYVVhbGV1UmRZ

NO.1 调度问题

  dp[i][j]表示处理第i个作业且A的总工作时间为j时B的总工作时间

  则对于每一个i,如果j<a[i](A的总时间还不能处理i),因为不得不处理,因此只能由B处理

dp[i][j]=dp[i-1][j]+b[i]

  否则A,B都可以处理 dp[i][j]=min(dp[i-1][j]+b[i],dp[i-1][j-a[i]])

dp[i-1][j]+b[i]:如果第i个处理是B做的,那么A的总工作时间不变,因此i-1与i时的j是相等的

dp[i-1][j-a[i]]:此时是A做,所以B不做,B的总工作时间就等于i-1是B的总时间,也就是当A的工作时间为j-a[i]时

最后枚举A的时间,每次取A,B中的较大值

Code

 #include<bits/stdc++.h>
using namespace std;
int n, a[1005], b[1005], ans, sum, dp[1005][1005];//到第i个时j:A的工作时间 dp[i][j]:B的工作时间
int main() {
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),sum+=a[i];
for(int i=1;i<=n;i++)
scanf("%d",&b[i]);
memset(dp, 0x3f, sizeof(dp));
dp[0][0]=0;
for(int i=1;i<=n;i++){
for(int j=0;j<=sum;j++){
if(j<a[i])
dp[i][j]=dp[i-1][j]+b[i];
else
dp[i][j]=min(dp[i-1][j]+b[i],dp[i-1][j-a[i]]);
}
}
ans = 0x3f3f3f3f;
for(int i=0;i<=sum;i++){
if(i < dp[n][i]){
ans = min(ans, dp[n][i]);
}else{
ans = min(ans, i);
}
}
printf("%d",ans);
return 0;
}

NO.2 编辑距离

题目简述:

  题目让我们把字符串B通过插入删除修改一个字符三种方式变化为字符A,求最少操作次数。此处求的是最值,考虑用动态规划

定义状态:

  dp [ i ] [ j ] 表示使B [ 1 ~ j ] 与 A [ 1 ~ i ]变相等要花的值,最后的答案即为dp [ lenb ] [ lena ]

状态转移:

所有的动态规划题都是从已知推向未知的过程。因此我在思考一个dp时,总是从最后一个阶段着点。 对于此题,首先是边界:

①i==0时,即a为空,那么对应的dp[j][0]的值就为i:减少i个字符,使b转化为a

②j==0时,即b为空,那么对应的dp[0][i]的值就为j:增加j个字符,使b转化为a

if

当A[ i ]==B[ j ]时,dp[ i ][ j ]=dp[ i - 1 ] [ j - 1 ]

( 如果这两位相等,意思是使 i 位与 j 位相等不需要任何代价,只需要计算使 i - 1 位与 j - 1 位相等的代价 )

else

  删操作 : 如果删除B [ j ] 这一位,就要使B [ 1 ~ j -1 ]与A [ 1 ~ i ] 匹配. 字符串B的前j-1个字符变为字符串A的前i个需要多少步 (把字符串的第j个字符(最后一个)删除了),删除需要一步因此加1.dp [ i ] [ j ] = dp [ i ] [ j - 1] + 1

插入操作 : 插入就是删除嘛…… 插入一个B [ j + 1],使B [ j + 1 ]匹配A [ i ],那么就要使B [ 1 ~ j ]与A [ 1 ~ i - 1 ] 匹配dp [ i ] [ j ] = dp [ i -1 ] [ j ] + 1;

替换操作 : 把B[ j ]替换成能与A[ i ]匹配的数,字符串A和B的最后两个都相等了,因此都不用再考虑,字符串A的前i-1个字符变为字符串B的前j-1个需要多少步 添加需要一步因此加1, dp[ i ][ j ]=dp[ i - 1 ] [ j - 1 ] + 1

将以上三种情况的最小值作为dp [ i ] [ j ] 的值

Code

 #include<bits/stdc++.h>
using namespace std;
char a[105],b[105];
int lena,lenb,dp[105][105];
int main(){
scanf("%s\n%s",a+1,b+1);
lena=strlen(a+1),lenb=strlen(b+1);
for(int i=1;i<=lena;i++)dp[i][0]=i;
for(int i=1;i<=lenb;i++)dp[0][i]=i;
for(int i=1;i<=lena;i++){
for(int j=1;j<=lenb;j++){
if(a[i]==b[j])dp[i][j]=dp[i-1][j-1];
else dp[i][j]=min(dp[i-1][j-1],min(dp[i][j-1],dp[i-1][j]))+1;
}
}
cout<<dp[lena][lenb];
return 0;

NO.3 传纸条

  设f[i][j][k][l]为从小渊传到小轩的纸条到达( i , j ), 从小轩传到小渊的纸条到达( k , l )的路径上取得的最大的好心程度和。

完全可以换一个思路想,即求从给定的起点出发到指定的位置的两条最短严格不相交路线,那么显然,

对于每一步有四种情况:

  1.第一张纸条向下传,第二张纸条向下传;

  2.第一张纸条向下传,第二张纸条向右传;

  3.第一张纸条向右传,第二张纸条向下传;

  4.第一张纸条向右传,第二张纸条向右传;

转移方程是:f[i][j][k][l]=max( f[i][j-1][k-1][l] , f[i-1][j][k][l-1] , f[i][j-1][k][l-1] , f[i-1][j][k-1][l] )+a[i][j]+a[k][l]

Code

 #include <bits/stdc++.h>
using namespace std;
int f[55][55][55][55],a[55][55];
int n,m;
int main(){
cin >> n >> m;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
cin>>a[i][j];
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
for (int k=1;k<=n;k++)
for (int l=1;l<=m;l++)
if(i!=k&&j!=l)
f[i][j][k][l]=max(max(f[i][j-1][k-1][l],f[i-1][j][k][l-1]),max(f[i][j-1][k][l-1],f[i-1][j][k-1][l]))+a[i][j]+a[k][l];
cout << f[n][m-1][n-1][m];
return 0;
}

No.4 释放囚犯

  区间dp的套路:设f[i][j]为区间释放i~j号囚犯所需最少的肉(注意,i,j不是牢房编号,是释放的囚犯编号,也就是下面的a[i]数组)

  枚举区间的分界点k,转移方程为:

  f[i][j]=min{f[i][j],f[i][k-1]+f[k+1][j]+a[j+1]-a[i-1]-1-1}

  把后面这一坨拿出来拆开看看,

  f[i][k-1]+f[k+1][j],这个不必解释

  a[j+1]-a[i-1]-1就是第j+1个要放出的囚犯到第i-1个要放出的囚犯之间的人数,也就是要发的肉的数量;

  最后一个-1 是什么呢,就是第k个放出去的囚犯,不用给他吃肉了

  注意一件事:输入的囚犯的编号。当你细细的观察它们时,你会发现第 Qi​ 个囚犯的编号Qi​ 等于他及其前面的所有人的人数,那么这就相当于是一个前缀和,又因为我们放第 Qq 个囚犯的时候需要给最后一段人肉,所以我们可以假设在这段监狱的最后(p+1)还有一个需要释放的囚犯。

  再假设我们此时释放囚犯 k,那么我们此时需要的肉的数量即为释放第 Qi​ 个囚犯到第 Qk−1​ 个囚犯与释放第 Qk+1​ 个囚犯到第 Qj​ 个囚犯所需的总肉数加上施放这个囚犯所需的肉的数量。由于我们先选择释放第Qk​ 个囚犯,所以我们需要用 a[j+1]-a[i-1]-2 的肉(我们的假设是除了第 Qi​ 个囚犯到第 Qj​ 个囚犯未释放外其他囚犯均已释放,只不过没用肉。),由于先放哪一个囚犯最优不清楚,于是取最小值。

Code

 #include<bits/stdc++.h>
using namespace std;
int a[105];
int dp[105][105];
int main()
{
int p,q;
scanf("%d%d",&p,&q);
for(int i=1;i<=q;i++)
scanf("%d",&a[i]);
a[0]=0;
a[q+1]=p+1;
sort(a+1,a+q+1);
for(int len=1;len<=q;len++)
{
for(int i=1;i+len-1<=q;i++)
{
int j=i+len-1;
dp[i][j]=0x3f3f3f3f;
for(int k=i;k<=j;k++)
dp[i][j]=min(dp[i][j],dp[i][k-1]+dp[k+1][j]+a[j+1]-a[i-1]-2);
}
}
printf("%d",dp[1][q]);
return 0;
}

No.5 Number Triangles

  水,大佬请绕步

  分析题干,发现从上面往下一步步走很麻烦,直接搜索肯定超时。所以,逆向求解

  放水题好心虚啊

Code

 #include <bits/stdc++.h>
using namespace std;
int a[1005][1005],dp[1005][1005];
int main() {
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) {
for(int j=1;j<=i;j++) {
scanf("%d",&a[i][j]);
}
}
for(int i=n;i>=1;i--) {
for(int j=i;j>=1;j--) {
dp[i][j]=max(dp[i+1][j],dp[i+1][j+1])+a[i][j];//左下,右下
}
}
printf("%d",dp[1][1]);
return 0;
}

DP の 百题大过关(5/100)的更多相关文章

  1. dp百题大过关(第一场)

    好吧,这名字真是让我想起了某段被某教科书支配的历史.....各种DP题层出不穷,不过终于做完了orz 虽然各种手糊加乱搞,但还是要总结一下. T1 Monkey Banana Problem    这 ...

  2. DP百题练(一)

    目录 DP百题练(一) 线性 DP 简述 Arithmetic Progressions [ZJOI2006]物流运输 LG1095 守望者的逃离 LG1103 书本整理 CH5102 移动服务 LG ...

  3. DP百题练(二)

    目录 DP百题练(二) 区间 DP NOI1995 石子合并 IOI1998 Polygon CH5302 金字塔 USACO06FEB Treats for the Cows G/S LG1043 ...

  4. DP百题练(三)

    目录 DP百题练(三) DP百题练(三) 不知不觉也刷了 50 道 DP 题了,感觉确实有较大的进步.(2020.3.20) 这里的 (三) 主要用来记录 DP 的各种优化(倍增.数据结构.斜率.四边 ...

  5. DP百题练索引

    就是一篇还在咕的文章 DP百题练(一) DP百题练(二) DP百题练(三)

  6. dp杂题(根据个人进度选更)

    ----19.7.30 今天又开了一个新专题,dp杂题,我依旧按照之前一样,这一个专题更在一起,根据个人进度选更题目; dp就是动态规划,本人认为,动态规划的核心就是dp状态的设立以及dp转移方程的推 ...

  7. [poj2247] Humble Numbers (DP水题)

    DP 水题 Description A number whose only prime factors are 2,3,5 or 7 is called a humble number. The se ...

  8. 历代诗词咏宁夏注释3----蔡升元:<题大清渠>

    题大清渠 蔡升元 为怜□□□□□,□□□□□□□. □□□□沙碛里,凿开峡口贺兰旁. 支分九堡通沟浍,鼎峙三渠并汉唐. 作吏尽如君任事,不难到处乐丰穰. 两渠中划大清渠,畚筑无劳民力纾.[1] 心画万 ...

  9. Vijos1057 盖房子(DP经典题)

    之前没有怎么刷过dp的题,所以在此学习了~(感谢walala大神的思路,给了我很大的启发) 也算是自己学习的另一种dp题型吧 先贴上状态转移方程: if(a[i][j]) f[i][j]=min(f[ ...

随机推荐

  1. NLP教程(6) - 神经机器翻译、seq2seq与注意力机制

    作者:韩信子@ShowMeAI 教程地址:http://www.showmeai.tech/tutorials/36 本文地址:http://www.showmeai.tech/article-det ...

  2. 204. Count Primes - LeetCode

    Queston 204. Count Primes Solution 题目大意:给一个数,求小于这个数的素数的个数 思路:初始化一个boolean数组,初始设置为true,先遍历将2的倍数设置为fal ...

  3. python操作MySQL与MySQL补充

    目录 python操作MySQL 基本使用 SQL注入问题 二次确认 视图 触发器 事务 存储过程 函数 流程控制 索引 练习 python操作MySQL python中支持操作MySQL的模块很多, ...

  4. node-sass,sass-loader和node之间的关系

    vue-cli运行在node平台上scss语言是运行在 node-sass平台上node-sass的运行环境是node平台vue-cli工程中不识别scss语法,.scss模块,sass-loader ...

  5. Hadoop入门学习笔记(二)

    Yarn学习 YARN简介 YARN是一个通用资源管理系统和调度平台,可为上层应用提供统一的资源管理和调度 YARN功能说明 资源管理系统:集群的硬件资源,和程序运行相关,比如内存.CPU等. 调度平 ...

  6. ACM 刷题记录

    HDU Multi-University Training Contest 题目来源 题目 知识点 时间复杂度 完成情况 2019 Contest8 A Acesrc and Cube Hyperne ...

  7. C/C++ 单元自动化测试解决方案实践

    vivo 互联网服务器团队 - Li Qingxin C/C++ 开发效率一直被业内开发人员诟病,单元测试开发效率也是如此,以至于开发人员不愿花时间来写单元测试.那么我们是不是可以通过改善编写单元测试 ...

  8. 干货合集│最好用的 python 库都在这

    一.分词 - jieba 优秀的中文分词库,依靠中文词库,利用词库确定汉子之间关联的概率,形成分词结果 import jieba word = '伟大的中华人民共和国' jieba.cut(word) ...

  9. Eclipse For Java开发环境部署

    Eclipse For Java开发环境部署 1.准备工作 jdk安装包 jdk官网下载 Eclipse安装包 Eclipse官网下载 Eclipse下载时选择图中所示的国内镜像地址下载 下载后的文件 ...

  10. Nginx安装及支持https代理配置和禁用TSLv1.0、TSLv1.1配置

    Linux安装Nginx Nginx安装及支持https代理配置和禁用TSLv1.0.TSLv1.1配置. 下载安装包 [root@localhost ~]# wget http://nginx.or ...