动态规划

动态规划训练之二十

大憨熊 提交于 2019-12-03 20:44:31
https://www.luogu.org/problem/P1370 题目大意:Σ(1<=l<=r<=n)F(l, r),其中F(l,r)表示[l,r]之间的本质不同的子序列有多少个 分析: 如果本题数据是N^2^的话我就会做,但是要求是O(n)求出 同样的 区间计数题 , 固定端点L ,再 考虑dp 设dp[i]表示F[i,i]+F[i,i+1]+F[i,i+2]+....+F[i,n] 如果没有重复的数字话 dp[i]=(dp[i+1]<<1)+2 意思是: dp[i+1]= F[i+1,i+1]+F[i+1,i+2]+F[i+1,i+3]+....+F[i+1,n] dp[i]= F[i,i]+ F[i,i+1]+ F[i,i+2]+ F[i,i+3] +....+ F[i,n] 相信一看就懂把 但是有重复怎么办? 若ai==aj(i<j) 则dp[i]-=dp[j+1]+1; 原因是 后面所有的F[j+1,j+1].....都会有一次重复(接ai,接aj) 那个1就是F[j,j]中选j或不选j中的选j的方案 code(代码懒得打了): #include<bits/stdc++.h> using namespace std; #define ll long long #define mod 998244353 #ifdef ONLINE_JUDGE char *TT,*mo

动态规划之免费馅饼详解

99封情书 提交于 2019-12-03 20:16:54
/* 动态规划满足整体最优解可以由子结构局部最优解推出,从小到大一步一步推往前或者往后推。 * * 实际上做题的时候,就是把每种情况下小的最优解存起来 ,供下一个更大规模的局部去选择最优解,然后再存起来这种更大规模的各种情况下最优解。 * 一层一层存起来去推,最后就能求得最后你需要规模的最优值 * * 此题dp就是用来存局部最优解的 * dp【n】【1,2,3.....】就是n规模存1 ,2 ,3......这几种位置情况各自能再接到最多的馅饼(明显这里还能接再得到最多馅饼就是最优意思) * dp【n-1】【1,2,3......】就是扩大规模变为n-1后1,2,3....这几种位置情况下还能在接到的馅饼 * (n-1之所以比n规模大,是考虑实际情况,n-1时刻到endTime时刻明显比n增加了1,时间长还能接到的饼多,当然算是规模大了) * (求最优n规模必须经过最优n-1规模,说明就存在最优子结构关系) * * * dp二维数组具体表示 从t时刻起到最后一刻时间,x位置还能再接的最多的饼数(注意是还能再接,且是最多),题目总共有是一个位置,故x为11 * * exactly 二维数组 存 x位置,在t时刻,头顶上会掉多少个饼 * * dp最优子结构性质公式:dp[x,t]=exactly[x,t] + max{dp[x,t+1],dp[x-1,t+1],dp[x+1,t+1]}

算法第三章作业

可紊 提交于 2019-12-03 15:28:36
一、对动态规划算法的理解 动态规划其实与分治法类似,也是把一个问题分解成多个子问题,但是分治法在求解子问题时往往会有很多重复的计算,就会造成大量的时间浪费,而动态规划做的就是将这些子问题的计算结果保存起来,当需要用到的时候就可以直接调用,然后就是通过这样一种方式,一层层的求解,最后得出整个问题的结果。 二、递归方程 1 .单调递增最长子序列 2 .租用游艇问题 三、结对编程情况 结对编程效果显著,很多时候一个问题由一个人想可能想破脑袋都想不出来,但是如果多一个人跟你一起想的话情况就会有很大的不同,因为往往一句不经意的话就可能给双方带来灵感,这次的作业题就是这样的情况,一开始我完全没有解题的思路,直到之后跟同学讨论了一下之后,瞬间醍醐灌顶,对动态规划的理解加深了很多,然后举一反三,一口气就把几道题做完了。 来源: https://www.cnblogs.com/Raido/p/11802293.html

动态规划(4)--------仍然是一个简单的例子

耗尽温柔 提交于 2019-12-03 15:27:48
给定一个三角形,找出自顶向下的最小路径和。每一步只能移动到下一行中相邻的结点上。 例如,给定三角形: [ [2], [3,4], [6,5,7], [4,1,8,3] ] 自顶向下的最小路径和为 11(即,2 + 3 + 5 + 1 = 11)。 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/triangle 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 经过上几次的分析,我们应该知道了,动态规划的关键是找到状态转移方程。对于此问题,我想状态转移方程是很明显的。节点[i,j],选择min([i-1,j],[i-1,j-1]),然后加上自己的数。注意,题干说的相邻指的是节点[i,j]和节点[i+1,j],[i+1,j+1]相邻。那么此处将会有两种解法,自顶向下和自底向上,显然,对于自顶向下,我们需要选择min([i-1,j],[i-1,j-1]),但是此处存在一个问题,即,上层比下层长度短,那么越界问题必然需要注意,此外还有j-1,需要单独讨论j=0的情况, 下面先给出自顶向下的代码 public int minimumTotal(List<List<Integer>> triangle) { int rows = triangle.size(); if(rows == 0) return 0; int

python | 动态规划

元气小坏坏 提交于 2019-12-03 15:27:38
# encoding: utf-8 #题目是:在arr中选出一堆数字,选出的数字不能是与它相邻的,然后使得选出的数字之和最大 import numpy as np arr=[1,2,4,1,7,8,3] #递归写法 def rec_opt(arr,i): if i==0: return arr[0] elif i==1: return max(arr[0],arr[1]) #为什么这里返回的是相邻两个之中的最大值? #这不是违背条件了吗? else: A = rec_opt(arr,i-2)+arr[i] B = rec_opt(arr,i-1) return max(A,B) #非递归写法 def dp_opt(arr): opt = np.zeros(len(arr)) #创建一个数组大小等于arr,并且以零填充 opt[0]=arr[0] opt[1]=max(arr[0],arr[1]) for i in range(2,len(arr)): A = opt[i-2]+arr[i] B = opt[i-1] opt[i]=max(A,B) return opt[len(arr)-1] if __name__ == "__main__": print(rec_opt(arr,6)) print(dp_opt(arr))    #encoding=utf-8

关于动态规划的一些感想

邮差的信 提交于 2019-12-03 14:20:53
原文链接:https://leetcode-cn.com/problems/maximum-subarray/solution/xiang-xi-jie-du-dong-tai-gui-hua-de-shi-xian-yi-li/ 通常我们遍历子串或者子序列有三种遍历方式 1.  以某个节点为开头的所有子序列: 如 [a],[a, b],[ a, b, c] ... 再从以 b 为开头的子序列开始遍历 [b] [b, c]。 2.  根据子序列的长度为标杆,如先遍历出子序列长度为 1 的子序列,在遍历出长度为 2 的 等等。 3.  以子序列的结束节点为基准,先遍历出以某个节点为结束的所有子序列,因为每个节点都可能会是子序列的结束节点,因此要遍历下整个序列,如: 以 b 为结束点的所有子序列: [a , b] [b] 以 c 为结束点的所有子序列: [a, b, c] [b, c] [ c ]。 第一种遍历方式通常用于暴力解法, 第二种遍历方式 leetcode (5. 最长回文子串 ) 中的解法就用到了。 第三种遍历方式 因为可以产生递推关系, 采用动态规划时, 经常通过此种遍历方式, 如 背包问题, 最大公共子串 , 这里的动态规划解法也是以 先遍历出 以某个节点为结束节点的所有子序列 的思路 来源: https://www.cnblogs.com/da-peng/p

Common Subsequence

最后都变了- 提交于 2019-12-03 14:02:28
L - Common Subsequence 参考: ACM POJ 1458 Common Subsequence (最长公共子序列,动态规划) 思路:二维动态规划。 dp[i][j] :在截止至 s1 的 i-1 , s2 的 j-1 位置,两个串的最长公共子序列长度。 动态规划方程: if(s1[i]==s2[j]) dp[i+1][j+1]=dp[i][j]+1; else dp[i+1][j+1]=max(dp[i][j+1],dp[i+1][j]); 即如果 s1[i]==s2[j] ,则表示当前最长公子序列可加1,若不相等,则为前面的状态的 dp 最大值。 代码: // Created by CAD on 2019/11/5. #include <iostream> #include <string> using namespace std; int dp[1005][1005]; int main() { ios::sync_with_stdio(false); cin.tie(0); string s1,s2; while(cin>>s1>>s2) { int len1=s1.length(),len2=s2.length(); for(int i=0;i<=len1;++i) dp[i][0]=0; for(int i=0;i<=len2;++i) dp[0]

算法第三张作业

时间秒杀一切 提交于 2019-12-03 13:59:42
1. 你对动态规划算法的理解 我觉得动态规划算法其实与分治法有很多相似之处,都是先要将问题分解成子问题再进行解决,而动态规划更多是子问题之间有联系,一个子问题的解决有可能需要依赖其他子问题,而要解决整个问题需要先分析找出子问题的联系然后写出递归方程,最后再填表或者用递归方法求解。动态规划算法运用到了最优子结构的性质。 2. 分别列出编程题1、2的递归方程 1. b[i] = 1 , 0 <= i < n(赋初始值) (b[i]表示第i项单调递增子序列长度) b[i] = max(b[j]+1, b[i]) a[i]>a[j] 且 0 <= j < i - 1(对于第i项之前的每一项都要比较,取多次比较后的最大值) 2.b[j][j + i] 表示以第j站为起点,到相差为i的出租站的最少租金(b[1][1 + 1]即b[1][2]表示从第一站到相差一站的站点,即第二站的最低租金) b[j][j + i] = a[j][j + i],(赋初始值) b[j][j + i] = a[j][j + i], i = 1(相差一站时只有一种情况) b[j][j + i] = min(b[j][k] + b[k][j+i], b[j][j + i]) ,i > 1 且 j < k < j + i (利用最优子结构性质可知从j站到j + i站最多只能中转一次,设第k站为中转站,取多次比较后的最小值)

第三章作业

爱⌒轻易说出口 提交于 2019-12-03 13:33:46
1. 你对动态规划算法的理解 将复杂的问题逐步简单化,这就是动态规划思想 动态规划三要素: 1) 最优子结构 用动态规划求解最优化问题的第一步就是刻画最优解的结构,如果一个问题的解结构包含其子问题的最优解,就称此问题具有最优子结构性质 2) 边界 f(1) = 1,f(2) = 2这两个是问题的边界,如果没有边界,无法得出结果 3) 状态转移公式 状态转移公式就是定义了每一阶段与下一阶段的关系 2. 分别列出编程题1、2的递归方程 编程题1:a[i][j]=min{ a[i-1][j-1], a[i-1][j] } 1<i<=n,1<=j<=i; 编程题2: a[i] = max{ a[i-1]+a[i], a[i] } 1<=i<=n; 3. 说明结对编程情况(1分) 目前结对编程情况良好,互帮互助,结伴队友和我对编程有不同的思维方式和思考习惯,反而让我们扩宽了思维。 来源: https://www.cnblogs.com/smclrh35665632/p/11797307.html

DAG 上动态规划 - 点火(fire) 2019.8.8

可紊 提交于 2019-12-03 11:58:31
题面 【问题描述】 给出 \(n\) 个点(编号 \(1\) ~ \(n\) ), \(m\) 条单向边。现在同时所有从入度为零的点开始点火,引燃整个图。 点燃一个点就会引燃所有以这个点为出发点的边。 每一条边燃烧需要消耗一定时间。 当一个点的所有入度边全部烧完,才能点燃这个点。 求燃烧完整张图需要多少时间。 【输入格式】 第一行输入两个整数 \(n\) ( \(2\le n\le 100\) ), \(m\) ( \(1\le m\le 1000\) )。 接下来 \(m\) 行每行输入三个整数 \(x\) , \(y\) , \(c\) 表示有一条从 \(x\) 去到 \(y\) 的单向边燃烧完需要 \(c\) ( \(0<c\le 10000\) )个单位时间。 【输出格式】 输出需要的时间,数据保证有解,且图中无环。 【样例输入】 4 5 1 2 2 1 3 4 2 4 4 2 3 1 3 4 5 【样例输出】 9 解 即是对所有入度为 0 的节点为终点在反图上求最长路。 程序 #include <bits/stdc++.h> using namespace std; #define MAXN 120 int n, m, ideg[MAXN], odeg[MAXN], d[MAXN]; struct Edge { int d, w; Edge(int d = 0, int