第五周集训总结

动态规划

1.递推算法

例题 位数问题

【问题描述】
在所有的N位数中,有多少个数中有偶数个数字3?由于结果可能很大,你只需要输出这个答案对12345取余的值。

【输入格式】
读入一个数N

【输出格式】
输出有多少个数中有偶数个数字3。

【输入样例】
2
【输出样例】
73
【数据规模】
1<=N<=1000

【样例说明】
在所有的2位数字,包含0个3的数有72个,包含2个3的数有1个,共73个

理解

考虑这种题目,一般来说都是从第i-1位推导第i位,且当前位是取偶数还是取奇数的。
可以用f[i][0]表示前i位有偶数个3的方案数
f[i][1]表示前i位有奇数个3的方案数
则状态转移方程可以表示为:
f[i][0]=f[i-1][0]*9+f[i-1][1];
f[i][1]=f[i-1][0]+f[i-1][1]*9;
边界条件:f[1][1]=1; f[1][0]=8;

例题代码

#include <iostream>
using namespace std;
const int M=12345;//取模
const int N=1000+5; //最多1000位数
int main()
{
   
//f[i][0]表示前i位有偶数个3的方案数,f[i][1]表示前i位有奇数个3的方案数
int f[N][2],n;
f[1][0]=8;f[1][1]=1;//1位数的情况
cin>>n;
for(int i=2;i<=n;i++){
   
f[i][0]=(f[i-1][0]*9+f[i-1][1])%M;
f[i][1]=(f[i-1][1]*9+f[i-1][0])%M;
}
cout<<f[n][0]<<endl;
return 0;
}

2.基础dp

算法思想

如果各个子问题不是独立的,如果能够保存已经解决的子问题的答案,而在需要的时候再找出已求得的答案,这样就可以避免大量的重复计算。
基本思路是,用一个表记录所有已解决的子问题的答案,不管该问题以后是否被用到,只要它被计算过,就将其结果填入表中。

求解过程

在这里插入图片描述

基本步骤

动态规划算法通常用于求解具有某种最优性质的问题。在这类问题中,可能会有许多可行解。每一个解都对应于一个值,我们希望找到具有最优值(最大值或最小值)的那个解。

动态规划法设计算法一般分成三个阶段:
(1)分段:将原问题分解为若干个相互重叠的子问题;
(2)分析:分析问题是否满足最优性原理,找出动态规划函数的递推式;
(3)求解:利用递推式自底向上计算,实现动态规划过程。
动态规划法利用问题的最优性原理,以自底向上的方式从子问题的最优解逐步构造出整个问题的最优解。

滚动数组

•处理dp[][]状态数组的时候,有个小技巧:把它变成一维的dp[],以节省空间。
•观察二维表dp[][],可以发现,每一行是从上面一行算出来的,只跟上面一行有关系,跟更前面的行没有关系。
•那么用新的一行覆盖原来的一行就好了。

3.求最长递增子序列

1、暴力法:枚举所有的子序列,判断是不是递增的,如果是递增的求最大值。
2、采用LCS的方法:
1)原序列A排序得到B
2) 求A和B的LCS
3、直接DP
4、借助二分查找,优化为O(nlogn)

dp解法

先确定动态规划的状态,这个问题可以用序列某一项作为结尾来作为一个状态。
用dp[i]表示一定以第i 项为结尾的最长上升子序列。
用a[i] 表示第i 项的值
如果有j < i且a[j] < a[i],那么把第i 项接在第j 项后面构成的子序列长度为:dp[i] = dp[j] + 1。
•要使dp[i] 为以i 结尾的最长上升子序列,需要枚举所有满足条件的j。所以转移方程是:
在这里插入图片描述

3.递推与记忆化搜索

•前面DP的状态转移,都是用递推的方法。
•有另一种方法,逻辑上的理解更加直接,这就是用“递归+记忆化搜索”来实现DP。

记忆化搜索思想

用递归实现DP时,在递归程序中记录计算过的状态,并在后续的计算中跳过已经算过的重复的状态,从而大大减少递归的计算次数,这就是“记忆化搜索”的思路。

•递归时,有大量重复计算,其实能避免。
•观察第3层的中间数“1”,从第2层的“3”往下走会经过“1”,计算一次从“1”出发的递归;从第2层的“8”往下走会也经过“1”,又重新计算了从“1”出发的递归。所以,只要避免这些重复计算,就能优化。
7(30)
3(23) 8(21)
8(20) 1(13) 0(10)
2(7) 7(12) 4(10) 4(10)
4(4) 5(5) 2(2) 6(6) 5(5)

4.背包问题

1.0/1背包
2.完全背包
3.多重背包
4.混合背包
5.分组背包
6.依赖背包
我认为后面的背包问题都是由0/1背包问题衍生出来,所以把0/1背包问题思想理解透彻才是最根本的

0/1背包

一、定义状态:
a[i][j]:表示容量为j的背包选择前i件物品的最大价值和
二、状态转移方程
1、w[i] > j ,第i件物品太重了,容量为j的背包装不下
a[i][j] = a[i -1][j]
2、w[i] <= j
a[i][j] = max(a[i -1][j],a[i -1][j -w[i]] + v[i]);

理解

在0/1背包问题中,物品i或者被装入背包,或者不被
装入背包,设xi
表示物品i装入背包的情况,
则当xi=0时,表示物品i没有被装入背包,
xi=1时,表示物品i被装入背包。
根据问题的要求,有如下约束条件和目标函数:
在这里插入图片描述
按这样的规律一行行填表,直到结束。现在回头考虑,装了哪些物品。
看最后一列,15>14,说明装了物品5,否则价值不会变化。
在这里插入图片描述

#include<bits/stdc++.h>
intn,c;//n件物品,背包容量为c
intw[N],v[N];//重量是w,价值是V
cin>> n >> c;//读入物品数量n和背部的容量c
for(inti= 1;i <= n;i++)//读入每件物品的重量和价值
cin>> w[i] >> v[i];
//用dp方程建表,行表示物品[1,n],列表示背包容量[1,c]
//dp[i]表示容量为i的背包选择物品的最大价值和
intdp[N] = {
   0};//初始化表为0
//顺序遍历n件物品
for(inti= 1;i <= n;i++){
   
for(intj = c; j >= w[i]; j--){
   //背包容量[1,c],从右到左填表
//不选当前物品和选当前物品(背包容量变为j-w[i])两种方案求最大值
dp[j] = max(dp[j],dp[j -w[i]] + v[i]);
}
}

训练例题

数塔问题

题目描述

设有一个三角形的数塔,顶点为根结点,每个结点有一个整数值。从顶点出发,可以向左走或向右走,如图所示
在这里插入图片描述
若要求从根结点开始,请找出一条路径,使路径之和最大,只要输出路径的和。

输入

第一行为n(n<10),表示数塔的层数

从第2行至n+1行,每行有若干个数据,表示数塔中的数值

输出

输出路径和最大的路径值。

样例输入

5
13
11 8
12 7 26
6 14 15 8
12 7 13 24 11

样例输出

86

#
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android是一种基于Linux内核(不包含GNU组件)的自由及开放源代码的移动操作系统,主要应用于移动设备,如智能手机和平板电脑。该系统最初由安迪·鲁宾开发,后被Google公司收购并注资,随后与多家硬件制造商、软件开发商及电信营运商共同研发改良。 Android操作系统的特点包括: 开放源代码:Android系统采用开放源代码模式,允许开发者自由访问、修改和定制操作系统,这促进了技术的创新和发展,使得Android系统具有高度的灵活性和可定制性。 多任务处理:Android允许用户同时运行多个应用程序,并且可以轻松地在不同应用程序之间切换,提高了效率和便利性。 丰富的应用生态系统:Android系统拥有庞大的应用程序生态系统,用户可以从Google Play商店或其他第三方应用市场下载和安装各种各样的应用程序,满足各种需求。 可定制性:Android操作系统可以根据用户的个人喜好进行定制,用户可以更改主题、小部件和图标等,以使其界面更符合个人风格和偏好。 多种设备支持:Android操作系统可以运行在多种不同类型的设备上,包括手机、平板电脑、智能电视、汽车导航系统等。 此外,Android系统还有一些常见的问题,如应用崩溃、电池耗电过快、Wi-Fi连接问题、存储空间不足、更新问题等。针对这些问题,用户可以尝试一些基本的解决方法,如清除应用缓存和数据、降低屏幕亮度、关闭没有使用的连接和传感器、限制后台运行的应用、删除不需要的文件和应用等。 随着Android系统的不断发展,其功能和性能也在不断提升。例如,最新的Android版本引入了更多的安全性和隐私保护功能,以及更流畅的用户界面和更强大的性能。此外,Android系统也在不断探索新的应用场景,如智能家居、虚拟现实、人工智能等领域。 总之,Android系统是一种功能强大、灵活可定制、拥有丰富应用生态系统的移动操作系统,在全球范围内拥有广泛的用户基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值