首页 > 其他分享 >动态规划与搜索练习

动态规划与搜索练习

时间:2024-08-03 20:19:12浏览次数:15  
标签:动态 seq 最大值 练习 搜索 购买 ans 序列 total

这是我搜集到的一些动态规划和搜索的练习题

搜索小练习
动态规划小练习
祝你CSP拿到\(^{一等奖}_{一等奖}\)!


这是解析

动态规划

一、双子序列最大和

由于两个子序列不重叠,显然的这两个子序列之间一定有一个断点。要求两个子序列之和最大值,可以枚举断点的位置,对比每个断点下左序列和右序列的最大值之和,最大的即为答案。
接下来该怎么求解每一个左序列的最大值和右序列的最大值呢?在这样的数据规模下必然是已经打出了两个序列在每个断点处的最大值的一张表,每次掉用只花常数时间。求解左序列在每个断点的最大值这个问题,很容易想到用dp思想求解单序列最大值,那么常规操作:定义状态 f( i ) 为以序列第 i 个数为结尾的序列最大值。
不过上述步骤还没得出左序列在每个断点处最大值的表,它得到的是以断点左端点为结尾的左序列的最大值,而在实际情况中,左序列最大值不一定以断点左端为结尾,所以需要更新这个数组 f ,用 f[i] = max(f[i], f[i - 1]) 这样一个语句就可以实现更新(其实这个操作就像求解单序列最大值最后需要遍历一遍数组找出最大值一样,因为真正的最大序列不一定以最后一个数为结尾)。
对于右序列,只需倒着操作就可实现。

二、小猪购物

见NOIP-2018-提高组初赛-23-小猪购物.pdfNOIP-2018-提高组初赛-23 小猪购买N 件商品问题详解
作者:严老师
完善程序。
一只小猪要买N 件物品(N 不超过1000)。
它要买的所有物品在两家商店里都有卖。第i 件物品在第一家商店的价格是
a[i] ,在第二家商店的价格是b[i] ,两个价格都不小于0 且不超过10000。
如果在第一家商店买的物品的总额不少于50000,那么在第一家店买的物品都
可以打95 折(价格变为原来的0.95 倍)。
求小猪买齐所有物品所需最少的总额。
输入:第一行一个数N。接下来N 行,每行两个数。第i 行的两个数分别代表
a[i],b[i]。
输出:输出一行一个数,表示最少需要的总额,保留两位小数。
试补全程序。

#include <cstdi>
#include <cstdlib>
using namespace std;
const int Inf = 1000000000;
const int threshold = 50000;
const int maxn = 1000;
int n, a[maxn], b[maxn];
bool put_a[maxn];
int total_a, total_b;
double ans;
int f[threshold];
int main() {
scanf("%d", &n);
total_a = total_b = 0;
for (int i = 0; i < n; ++i) {
scanf("%d%d", a + i, b + i);
if (a[i] <= b[i]) total_a += a[i];
else total_b += b[i];
}
ans = total_a + total_b;
total_a = total_b = 0;
for (int i = 0; i < n; ++i) {
if ( ① ) {
put_a[i] = true;
total_a += a[i];
} else {
put_a[i] = false;
total_b += b[i];
}
}i
f ( ② ) {
printf("%.2f", total_a * 0.95 + total_b);
return 0;
}f
[0] = 0;
for (int i = 1; i < threshold; ++i)
f[i] = Inf;
int total_b_prefix = 0;
for (int i = 0; i < n; ++i)
if (!put_a[i]) {
total_b_prefix += b[i];
for (int j = threshold - 1; j >= 0; --j) {
if ( ③ >= threshold && f[j] != Inf)
ans = min(ans, (total_a + j + a[i]) * 0.95 + ④ );
f[j] = min(f[j] + b[i], j >= a[i] ? ⑤ : Inf);
}
}
printf("%.2f", ans);
return 0;
}

此题考查了贪心算法,动态规划-背包问题相关知识。
提示:对于完善程序题,建议先阅读程序,了解程序大致的思路,不要自己直接
读题后自行思考解决方法,除非是自己非常熟悉的题,否则,考试时建议直接读
程序,快速入手,节省时间,特别是对于题目给出的问题比较陌生,一下子想不
到好的方法的函数,读程序能发现一些常见的算法讨论模板,最后对于实在想不
出来的地方,可以根据代码的对称结构,前后语句,猜测出来。
以本题为例,首先读懂题意,小猪买齐N 件商品,每件商品仅有两种选
择,要么在第一家商店(a 店)买,要么在第二家店(b 店)购买,两家价格不
同。其中a 店有优惠活动,若购买总额达到50000,则在该店购买的所有物品
都可以打95 折。求小猪买齐N 件商品花费总额最少是多少。
首先拿到题,既然要想总花费最少,第一感觉是贪心法,假设能活动a
店折扣,然后选便宜的买。按这样的假设选购后,再检查a 店的购买总额是否确
实能满足打折条件,若能满足,则假设成立,直接得到最优解,若不满足,则需
要再具体分析。
这是一个最初的想法,但显然还不能达到代码实现的程度,然后结合题
目的代码看,很明显。35~37 行有一个判断,然后直接输出结果,return 了,
表示找到最优解了,是满足某种条件下的最优解。肯定是假设a 店购买总额达到
N 情况下的解。a 店的每件物品价格变成原来的0.95 倍,在此基础上将a 店每
件物品打折后的价格与b 店比较,取更小的即可。所以空1 和空2 很明确了。
接下来的难点在于当前贪心法的假设不成立,也就是total_a<N,怎么
办?
那就试着将之前选择在b 店购买的物品,重新调整为在a 店购买,朝着
把a 店的购买总额凑足N 看看。
这样将面临3 个问题:
1、total_a=0 的情况
2、是否一定能保证能调整到a 店的购买总额凑足N?
3、假定能调整到满足优惠条件,怎样调整最好?
先看第1 个问题,若total_a=0,表示a 店打折之后所有物品还是都比
b 店贵,a 店的打折没意义了,直接按原价谁便宜选哪家,这种情况下,结果显
然就是全在b 店买。所以后面要继续分析的情况是0<total_a<N 的情况。
再看第2 个问题,显然不一定能保证,极端情况就是将之前选择在b 店
购买的物品,全部调整为在a 店购买,total_a 依然达不到N,那就可以同样无
视a 店折扣了,直接按原价选便宜的,跟问题1 的结论一样。
这对应于代码18-24 行,不考虑优惠,直接按便宜的挑选,得到的ans
作为最优解的初值,后面再判断是否有更优的解来更新ans。
再看第3 个问题,这个问题是整个问题的关键之处,如图所示分界线右
侧的物品,可以任选几件物品调整为在a 店购买,假定能调整到使之满足优惠条
件,肯定是可能有多种调整方法的。
一个大前提就是最终的购买总额要尽量小,因为调整是将0.95a[i]>b[i]
的物品,调整为在a 店购买,所以应该是以尽量少的调整,使total_a 恰好增加
到N,同时使得分到b 店的购买额也尽量小。
借用01 背包的思路,定义子问题状态f[i][j],其表示,对上图分界线右
侧满足0.95a[i]>b[i]的m 件物品集合,命名为E(i),其前i(1<=i<=n)件物品,
经过重新选购后,分到a 店的购买额恰好为j 时,分到b 店的最小购买额。
状态转移方程:f[i][j] = min{f[i-1][j]+b[i], f[i-1][j-a[i]]}
状态转移循环,i 从1 到n,f 优化为一维数组,j 从N-1 逆序递推至0,
因为total_a>0 且价格都是整数。因为问题定义为“恰好”,f[0]初值为0,其
他初值为inf。(这块不清楚的请复习01 背包基础知识)。
状态转移过程中的购买总额计算公式如下图所示,图中红色字体的
total_a'和total_b'是转移过程中两个店的购买总额计算公式。
而实际情况中,total_a 显然不一定能够恰好达到N,而是大于或等于N,
所以代码第47 行,每次状态转移之前,若找到一个f[j]!=Inf 可行解,都要试探
性的先判断一下total_a 若转移到下一状态的话是否可能达到N,因为此时还未
进行状态转移,所以f[j]代表的是f[i-1][j],就是物品集E(i-1),经过调整后,
分到b 店的购买额。
此刻,若第i 件物品若选择在a 店购买,则:
a 店的购买总额=原先的total_a + j + a[i]
b 店的购买总额=f[j] + 原先的total_b-total_b_prefix[i]
若a 店的购买总额达到N,则购买总额=a 店的购买总额*0.95+b 店购
买总额,将其与最优解初值ans 比较,取更小者更新ans,否则ans 不变,注
意ans 的初值就是。这样状态转移完毕之后,得到的ans 就是最终的最优解。

三、烽火传递

分析:
要用动态规划的方法解决。我们可以写出这样的方程:
f[i]:=min{f[j]}+a[i] (i-m<=j<=i-1)
我们想到了用单调队列进行优化,由于随着i的循环,每次只有一个i进入决策区间也只有一个i出决策区间,由于每次选取决策区间中的最小值,所以维护一个单调递增序列,每次取出队首元素即可。
为什么可以将队尾元素无情的删去呢?由于后进队的序列同时满足在原序列中的位置更靠后和其在动态规划中的价值更大。这样选取这个元素就要比选取之前的任何一个决策要优,所以之前被删掉的决策都是无用的。
这道题的本质就是用单调队列维护了决策本身的价值和其在原序列中位置的同时单调。
要特别注意单调队列中的值是决策在原决策序列中的位置。

补充:
设f[i]表示点燃当前位置烽火台,且前i个满足要求的最小代价。
显然就有f[i]=min(f[j])+a[i](i-m<=j<=i-1)。
当然,这会超时,所以要有优化。
优化一:肯定是从前m个里选小的,涉及到区间最小值,可用线段树,时间复杂度将为O(nlogm)。
优化二:同样因为要选前m个最小的,使用单调队列,队列里存有不超过m个长度单位的值,每次取队首,进队时维护队列使其单调不下降,复杂度将为O(n)。

四、最长回文子序列

函数lps(seq,i,j)的用途是求字符串seq中区间[i,j]上的最长回文子序列长度(即原问题的子问题)。
如果seq[i]==seq[j],则取区间[i+1,j-1]的最长回文子序列,再在两头分别加上seq[i]和seq[j]仍是回文的,因此长度等于lps(seq,i+1,j-1)+2。
否则,取两个区间[i,j-1]和[i+1,j]中最长回文子序列长度的较大值(因为此时seq[i]和seq[j]不能同时选)。
答案即为lps(seq,0,n-1)。

搜索

Task 1:

深搜一下每一步怎么走。

Task 2:

深搜一下每一位放哪个数。

Task 3:

注意到如果确定了整个第一行、整个第一列的数字,那么我们实际上可以一行行地推出整个棋盘。
那么我们只要搜索第一行、第一列一共至多20个数字,然后判断是否符合条件就行了。
搜索的时候可以按字典序搜,找到一个解就可以直接退出程序了。

Task 4:

对于泥潭,我们看做两个格子u、v,走进去时会到达u,u到v需要1s,然后再从v走出去。
于是直接从起点开始广搜。

标签:动态,seq,最大值,练习,搜索,购买,ans,序列,total
From: https://www.cnblogs.com/mike-666/p/18340988

相关文章

  • PAT 乙级 真题练习 1013 数素数
    问题描述:题目描述:1013数素数分数20  作者 CHEN,Yue  单位 浙江大学令Pi​表示第i个素数。现任给两个正整数M≤N≤104,请输出PM​到PN​的所有素数。输入格式:输入在一行中给出M和N,其间以空格分隔。输出格式:输出从PM​到PN​的所有素数,每10......
  • C语言:动态内存管理
    动态内存管理一、动态分配内存的必要性普通内存分配动态内存分配二、动态内存分配函数(一)malloc(二)calloc(三)realloc(四)free三、常见的错误(一)对空指针进行解引用操作(二)对动态分配空间越界访问(三)free释放动态分配空间的一部分(四)动态开辟内存忘记释放四、柔性数组(一)柔性数组......
  • 代码随想录算法训练营Day18 | Leetcode 530 二叉搜索树的最小绝对差 Leetcode 236 二
    前言今天有一道题目没写,二叉搜索树中的众数,有点太难理解了,先放一放。Leetcode530二叉搜索树的最小绝对差题目链接:530.二叉搜索树的最小绝对差-力扣(LeetCode)代码随想录题解:代码随想录(programmercarl.com)思路:二叉搜索树的性质是中序遍历为升序的,所以我们想找最小绝......
  • Python中动态类和动态方法的创建与调用
    借助于python的动态语言特性,很容易对对象进行添加方法或者属性,这也是python的灵活之一。动态生成类的属性及其方法在某些情况可能要根据不同的参数来动态生成不同的实例方法、静态方法、类方法。下面的例子中则展示了如何动态地向类中添加属性和方法。importtypesclassPers......
  • 【笔记】动态规划选讲:凸优化技术大赏 2024.8.3
    如果您是搜索引擎搜进来的。很抱歉,没有您需要搜索的题目的题解。典题\(n\)个物品的背包,重量在\(1\sim4\)之间,价值在\(1\sim10^9\)之间。\(n\leq10^5\)。Minkowski和会遇到不连续的问题。不妨按照\(i\bmod12\)划分dp数组,每个剩余系都是凸的。枚举拿了\(......
  • C++动态规划(01背包)
    例题1:有 N 个物品,从 1 到 N 编号。对于每个 i(1≤i≤N),物品 i 的重量是 wi​ 价值是 vi​。太郎决定从 N 个物品里选一些放进背包带回家。太郎的背包的容量是 W,因此放进背包的物品的总重量不能超过 W。求太郎带回家的物品的总价值可能达到的最大值。1.贪......
  • 【Java零基础视频教程】综合练习题(一)——基础练习
    文章目录基础练习飞机票打印素数生成验证码复制数组评委打分数字加密抽奖双色球基础练习飞机票机票价格按照淡季旺季、头等舱和经济舱收费、输入机票原价、月份和头等舱或经济舱。​按照如下规则计算机票价格:旺季(5-10月)头等舱9折,经济舱8.5折,淡季(11月到来年4月)......
  • 【算法】浅析深度优先搜索算法
    深度优先搜索算法:深入探索,穷尽可能1.引言在计算机科学中,深度优先搜索(Depth-FirstSearch,简称DFS)是一种用于遍历或搜索树或图的算法。这种算法会沿着一个分支走到底,直到这个分支结束,然后回溯到上一个分叉点,继续探索下一个分支。本文将介绍深度优先搜索算法的原理、实现方......
  • E25.【C语言】练习:修改二进制序列的指定位
    十进制13-->二进制01101现要求二进制序列的第5位修改为1,再改成0复习:逻辑运算非(NOT)(C语言:~)x==0,NOTx-->1;x==1,NOTx-->0与(AND)(C语言:&)x=0或1,xAND0-->0,0ANDx-->0或(OR)(C语言:|)x=0或1,xOR1-->1,1ORx-->1异或(XOR)(C语言:^)x==0或1,xXOR1-->NOTx和1XORx-->......
  • 「代码随想录算法训练营」第二十八天 | 动态规划 part1
    509.斐波那契数题目链接:https://leetcode.cn/problems/fibonacci-number/题目难度:简单文章讲解:https://programmercarl.com/0509.斐波那契数.html视频讲解:https://www.bilibili.com/video/BV1f5411K7mo题目状态:过!思路:当n=0时,返回0;当n=1时,返回1;当n>=2时,返回fib(......