DP の 百题大过关(5/100)
动态规划自古以来是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)的更多相关文章
- dp百题大过关(第一场)
好吧,这名字真是让我想起了某段被某教科书支配的历史.....各种DP题层出不穷,不过终于做完了orz 虽然各种手糊加乱搞,但还是要总结一下. T1 Monkey Banana Problem 这 ...
- DP百题练(一)
目录 DP百题练(一) 线性 DP 简述 Arithmetic Progressions [ZJOI2006]物流运输 LG1095 守望者的逃离 LG1103 书本整理 CH5102 移动服务 LG ...
- DP百题练(二)
目录 DP百题练(二) 区间 DP NOI1995 石子合并 IOI1998 Polygon CH5302 金字塔 USACO06FEB Treats for the Cows G/S LG1043 ...
- DP百题练(三)
目录 DP百题练(三) DP百题练(三) 不知不觉也刷了 50 道 DP 题了,感觉确实有较大的进步.(2020.3.20) 这里的 (三) 主要用来记录 DP 的各种优化(倍增.数据结构.斜率.四边 ...
- DP百题练索引
就是一篇还在咕的文章 DP百题练(一) DP百题练(二) DP百题练(三)
- dp杂题(根据个人进度选更)
----19.7.30 今天又开了一个新专题,dp杂题,我依旧按照之前一样,这一个专题更在一起,根据个人进度选更题目; dp就是动态规划,本人认为,动态规划的核心就是dp状态的设立以及dp转移方程的推 ...
- [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 ...
- 历代诗词咏宁夏注释3----蔡升元:<题大清渠>
题大清渠 蔡升元 为怜□□□□□,□□□□□□□. □□□□沙碛里,凿开峡口贺兰旁. 支分九堡通沟浍,鼎峙三渠并汉唐. 作吏尽如君任事,不难到处乐丰穰. 两渠中划大清渠,畚筑无劳民力纾.[1] 心画万 ...
- Vijos1057 盖房子(DP经典题)
之前没有怎么刷过dp的题,所以在此学习了~(感谢walala大神的思路,给了我很大的启发) 也算是自己学习的另一种dp题型吧 先贴上状态转移方程: if(a[i][j]) f[i][j]=min(f[ ...
随机推荐
- JuiceFS v1.0 beta3 发布,支持 etcd、Amazon MemoryDB、Redis Cluster
JuiceFS v1.0 beta3 在元数据引擎方面继续增强,新增 etcd 支持小于 200 万文件的使用场景,相比 Redis 可以提供更好的可用性和安全性.同时支持了 Amazon Memor ...
- sklearn机器学习-特征提取1
scikit-learn机器学习的特征提取部分较多nlp内容,故学到一半学不下去,看完nltk再来补上 scikit-learn机器学习的特征提取这一章感觉讲的不是特别好,所以会结合着来看 首先是Di ...
- Java课程课堂作业代码
前言 本文章只是单纯记录课堂老师布置的课堂作业代码,题目都比较简单,所以没有写解题思路,相信大家都能理解,当然其中有的解法和代码不是最优的,当时只是为了完成题目,后来也懒得改了,如果有不恰当或者不正确 ...
- 【多线程】守护线程 Daemon
守护线程 Daemon 线程分为用户线程和守护线程 虚拟机必须确保用户线程执行完毕 虚拟机不用等待守护线程执行完毕 如,后台记录操作日志,监控内存,垃圾回收等待.. 代码示例: /** * @Desc ...
- 渗透:dSploit
dSploit--开源的专业的Android平台安全管理工具包 只能在横屏模式下工作,即使你旋转你的设备也将继续保持横屏,如果你有一个应用程序,如旋转控制器,迫使每一个应用程序旋转,将导致dSploi ...
- django框架5
内容概要 模板语法之过滤器(类似于内置函数) 模板语法之标签(类似于流程控制) 自定义过滤器.标签.inclusion_tag 模板的导入 模板的继承 注释语法补充 前期数据准备(测试环境搭建) al ...
- django框架1
简介 1.前端 与用户打交道的界面 2.web框架 可以将前端和数据库整合到一起 3.数据库 专门用于存储数据 内容概要 纯手撸web框架 基于wsgiref模块 优化措施 动静态网 ...
- Number.prototype.toString()方法
Number.prototype.toString(radix)方法返回指定基数对应Number的字符串值 radix可选参数,值范围为2~36,转化基数,如果未指定,默认值为10,如果radix值不 ...
- BUUCTF-菜刀666
菜刀666 这题和之前做过的流量题不同,对我还是有些难度.看了看大佬的wp才做出来的 wireshark打开流量包,一开始只是单纯过滤http,包很多,看花了眼,看了好多也没觉得有啥异常. 后面才知道 ...
- 物联网?快来看 Arduino 上云啦
作者:HelloGitHub-Anthony 这里是 HelloGitHub 推出的讲解开源硬件开发平台 Arduino 的系列教程. 第一篇:Arduino 介绍和开发环境搭建 第二篇:制作温湿度显 ...