动态规划自古以来是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. Git拉取远程新分支

    1.查看本地分支  git branch 2.查看远程分支  git branch -a 3.如果要拉取的远程分支本地没有 git fetch 4.拉取远程新分支到本地 git checkout -b ...

  2. .net6.0 初探

    概述:大概的了解一下 dotnet 6.0 建立 MVC web项目的过程以及程序调用  结合 EF 框架进行简单 的CRUD 1.选择创建  MVC 的Web项目 2.框架类型选择 6.0 3. 6 ...

  3. Vue基础篇 之 v-model 模拟

    我们知道vue中 为简化表单输入 提供了v-model 的语法绑定 将 vue的属性和表单元素进行了双向绑定 大大简化了表单数据操作的数据绑定 那么v-model 是如何实现双向绑定的呢? 今天我们来 ...

  4. Kafka 消费者解析

    一.消费者相关概念 1.1 消费组&消费者 消费者: 消费者从订阅的主题消费消息,消费消息的偏移量保存在Kafka的名字是__consumer_offsets的主题中 消费者还可以将⾃⼰的偏移 ...

  5. 20212115朱时鸿-关于python技能树以及markdown编辑器的测评

    csdn的链接:https://blog.csdn.net/m0_68116569/article/details/124049366 计算机连接:https://gitee.com/zhu-shih ...

  6. 13. L1,L2范数

    讲的言简意赅,本人懒,顺手转载过来:https://www.cnblogs.com/lhfhaifeng/p/10671349.html

  7. 慢到不能忍?别忍了,Ubuntu 21.10 APT 源修改为华为云镜像源

    更新记录 2022年4月15日:本文迁移自Panda666原博客,原发布时间:2021年3月29日. 2022年4月15日:将源改为华为云,华为云更方便.Ubuntu从20.04更新到21.10. 切 ...

  8. 浅析Kubernetes架构之workqueue

    通用队列 在kubernetes中,使用go的channel无法满足kubernetes的应用场景,如延迟.限速等:在kubernetes中存在三种队列通用队列 common queue ,延迟队列 ...

  9. JS:条件语句1

    条件语句: 1.if...else if (condition1) { 当条件 1 为 true 时执行 } else { 当条件 1 不为 true 时执行 } if (condition1) { ...

  10. BUUCTF-RAR

    rar 看提示知道爆破压缩包的题,纯数字4位数拿出ARCHPR爆破即可.