动态规划

动态规划之背包问题(一)

匿名 (未验证) 提交于 2019-12-02 23:43:01
背包问题 动态规划之背包问题(一) 问题介绍 直观思维 普通递归 记忆搜索式递归 穷竭搜索式递归 如何插入一段漂亮的代码片 生成一个适合你的列表 创建一个表格 设定内容居中、居左、居右 SmartyPants 创建一个自定义列表 如何创建一个注脚 注释也是必不可少的 KaTeX数学公式 新的甘特图功能,丰富你的文章 UML 图表 FLowchart流程图 导出与导入 导出 导入 动态规划之背包问题(一) 背包问题是动态规划最经典的问题之一,这篇博客会初步探索背包问题,在后续系列会继续深入。 问题介绍 有n个物品,价值和重量分别为vi和wi,背包承重W,求装入背包的最大价值。 例子: n=4 w={2,1,3,2} v={2,2,4,3} W=5 输出 V=7(选择第0,1,3件物品或者第2,3件物品) 直观思维 在背包还放得下这件物品时,选与不选都试一下,选二者的较大值 在背包放不下这件物品的时候,直接跳过这件物品 例如上例 普通递归 直接输入1次 # ,并按下 space 后,将生成1级标题。 输入2次 # ,并按下 space 后,将生成2级标题。 以此类推,我们支持6级标题。有助于使用 TOC 语法后生成一个完美的目录。 记忆搜索式递归 强调文本 强调文本 加粗文本 加粗文本 标记文本 删除文本 引用文本 H 2 O is是液体。 2 10 运算结果是 1024.

动态规划:编辑距离

匿名 (未验证) 提交于 2019-12-02 23:38:02
题目描述 UNIX系统下有一个行编辑器ed,它每次只对一行文本做删除一个字符、插入一个字符或替换一个字符三种操作。例如某一行的内容是“ABC”,经过把第二个字符替换成“D”、删除第一个字符、末尾插入一个字符“B”,这三步操作后,内容就变成了“DCB”。即“ABC”变成“DCB”需要经过3步操作,我们称它们的编辑距离为3。 现在给你两个任意字符串(不包含空格),请帮忙计算它们的最短编辑距离。 输入描述: 输入包含多组数据。 每组数据包含两个字符串m和n,它们仅包含字母,并且长度不超过1024。 输出描述: 对应每组输入,输出最短编辑距离。 示例1 输入 ABC CBCD ABC DCB 输出 2 3 分析: 假设序列S和T的长度分别为m和n, 两者的编辑距离表示为 d p [ m ] [ n ] dp[m][n] d p [ m ] [ n ] . 则对序列进行操作时存在以下几种情况: a, 当S和T的末尾字符相等时, 对末尾字符不需要进行上述定义操作中(亦即"编辑")的任何一个, 也就是不需要增加计数. 则满足条件: d p [ m ] [ n ] = d p [ m 1 ] [ n 1 ] dp[m][n] = dp[m - 1][n - 1] d p [ m ] [ n ] = d p [ m 1 ] [ n 1 ] . b, 当S和T的末尾字符不相等时,

暴力递归和动态规划

匿名 (未验证) 提交于 2019-12-02 23:34:01
# 暴力递归和动态规划 求n!的结果 思路:要求n!,则要先求出(n-1)!,n*(n-1)! 即为n!的结果。要求(n-1)!,则要先・・・・・・ 代码 public class Factorial { public static int factorial(int num) { if (num == 1) { return 1; } return factorial(num - 1) * num; } public static void main(String[] args) { System.out.println(factorial(3)); } } 汉诺塔问题 题目:打印n层汉诺塔从最左边移动到最右边的全部过程 思路:分三步 先将1~n-1层从左边移到中间 再将第n层从左边移到最右边 最后再将1~n-1层从中间移到最右边 代码 /** * 汉诺塔问题 */ public class Hanoi { public static void hanoi(int N, String from, String to, String help) { if (N == 1) { System.out.println("move 1 from" + from + "to" + to); } else { hanoi(N-1,from,help,to); System.out

动态规划之最长公共子序列

匿名 (未验证) 提交于 2019-12-02 23:34:01
最长公共子序列,顾名思义,就是给定两个序列,求出其中长度最长的共有的子序列。如,给定1,2,4,5,6和2,4,5 显然2,4,5是最长的共有序列。 那么,如何分析此类问题呢? 老方法,我们仍要找出前后状态之间的联系。显然,这是给定了两个序列,那么肯定是开了一个二维 的数组,进行二维的遍历。 假设,a[n],b[m]是给定的序列。如果遍历的过程中,a[i]=b[j],那么显然这一状态等于前一状态加1,此时前一状态是dp[i-1][j-1]。 那如果a[i]!=b[j]的话,那么此时的最长值,是前一状态的最长值,所以这次我们得寻找前一状态。不加思考的话,我们很容易的得出前一状态是dp[i-1][j-1]。 其实这样是不对的,因为此状态与前一状态相比,b数组向后遍历了一位,那这引发的变化,使得前一状态有两组组合,即dp[i-1][j],dp[i][j-1],求出其中的最大,就可得到最终的结果。代码如下: #include <iostream> using namespace std ; int main (){ int n , m ; cin << n ; cin << m ; int a [ n ], b [ m ]; for ( int i = 1 ; i <= n ; i ++){ cin << a [ i ]; } for ( int i = 1 ; i <= m ; i ++

LeetCode 摘樱桃(动态规划)

匿名 (未验证) 提交于 2019-12-02 23:32:01
版权声明:本文为博主原创文章,博客地址:https://blog.csdn.net/qq_41855420,未经博主允许不得转载。 https://blog.csdn.net/qq_41855420/article/details/89763948 一个N x N的网格(grid) 代表了一块樱桃地,每个格子由以下三种数字的一种来表示: 0 表示这个格子是空的,所以你可以穿过它。 1 表示这个格子里装着一个樱桃,你可以摘到樱桃然后穿过它。 -1 表示这个格子里有荆棘,挡着你的路。 你的任务是在遵守下列规则的情况下,尽可能的摘到最多樱桃: 从位置 (0, 0) 出发,最后到达 (N-1, N-1) ,只能向下或向右走,并且只能穿越有效的格子(即只可以穿过值为0或者1的格子); 当到达 (N-1, N-1) 后,你要继续走,直到返回到 (0, 0) ,只能向上或向左走,并且只能穿越有效的格子; 当你经过一个格子且这个格子包含一个樱桃时,你将摘到樱桃并且这个格子会变成空的(值变为0); 如果在 (0, 0) 和 (N-1, N-1) 之间不存在一条可经过的路径,则没有任何一个樱桃能被摘到。 示例 1: 输入: grid = [[0, 1, -1], [1, 0, -1], [1, 1, 1]] 输出: 5 解释: 玩家从(0,0)点出发,经过了向下走,向下走,向右走,向右走,到达了点(2

流水作业 动态规划

匿名 (未验证) 提交于 2019-12-02 23:32:01
版权声明:沉迷代码,难以自拔 https://blog.csdn.net/qq_33846054/article/details/78196168 王晓东的《计算机算法设计与分析》上这一节我看的云里雾里,数学公式让我眼花缭乱。但是读懂数学公式的推导过程并不是最重要的事情。重要的是解题的思路! 我读懂了“流水作业”的题目要求,以及最优子结构性质 动态规划――流水作业调度问题 这里有流水作业的具体实例,很好地展示了自底向上的动规过程,C++代码 0018算法笔记――【动态规划】流水作业调度问题与Johnson法则 Java 代码,注释写的很详细 动态规划之流水作业调度Johnson法则 # include <iostream> # include <stdlib.h> using namespace std ; // 动态规划 流水作业调度问题 class Jobtype { public : int operator <= ( Jobtype a ) const { return ( key <= a . key ) ; } int key , index ; bool job ; } ; /* 定义作业Jobtype类: key : 关键字 index :索引值 bool job : a[i]<=b[i]的归入N1类,job值为1 ; 否则为0 重新定义运算符 <= */ int

动态规划

匿名 (未验证) 提交于 2019-12-02 23:30:02
斐波那契数列 F【0】、F【1】……F【N】   ->状态 书写代码方法: 顺着推/逆着推/记忆化搜索 代码示例: #include<iostream> using namespace std; int n,f[10086]; int main(){ /* *顺着推 */ cin>>n; f[0]=1; f[1]=1; for( int i=2 ; i<=n ; ++i ){ f[i]=f[i-1]+f[i-2]; } cout<<f[n]; /* *逆着推 */ cin>>n; f[0]=1; f[1]=1; for( int i=0 ; i<n ; ++i ){ f[i-1] += f[i]; f[i-2] += f[i]; } cout<<f[n]; return 0; } 记忆化搜索: #include<iostream> using namespace std; #define N 10086 int n; int f[N]; bool vis[N]; /* *搜索 */ int dfs( int n ){ if( n==0 ) return 1; if( n==1 ) return 1; return dfs(n-1)+dfs(n-2); }//O( f(n) ) /* *记忆化搜索 */ int dfs( int n ){ if( n==0 ) return 1;

动态规划入门_钱币兑换问题

匿名 (未验证) 提交于 2019-12-02 23:26:52
] ; 问题描述: Problem Description 在一个国家仅有1分,2分,3分硬币,将钱N兑换成硬币有很多种兑法。请你编程序计算出共有多少种兑法。 Input 每行只有一个正整数N,N小于32768。 Output 对应每个输入,输出兑换方法数。 Sample Input 2934 12553 Sample Output 718831 13137761 1 import java.util.Scanner; 2 3 public class Main { 4 5 public static void main(String[] args) { 6 7 Scanner cin = new Scanner (System.in); 8 while(cin.hasNext()){ 9 int n = cin.nextInt(); 10 int [] value = {1,2,3}; 11 int [] dp = new int [32800]; 12 13 dp [0] =1; 14 for(int i = 0;i<value.length;i++){ 15 for(int j = value[i];j<=n;j++){ 16 dp[j] = dp[j]+dp[j-value[i]]; 17 } 18 } 19 20 21 System.out.println(dp[n]);

八皇后问题---动态规划

匿名 (未验证) 提交于 2019-12-02 23:26:52
做了好多动态规划的题目,有了一些心得。 public int getanswer(char[][] map,int index,int n) { if(index==n) {// index==n 则意味的递归结束 /*System.out.println("-------------"); for(int i=0;i<n;i++) { System.out.println(map[i]); }//打印一些 可行的排列 System.out.println("--------------");*/ return -1;//返回-1 意味着递归的结束,或 递归失败 }else { for(int i=0;i<n;i++) {//遍历该次 皇后可行的位置 if(isOk(i, index, map)) { map[index][i]='Q'; if(getanswer(map, index+1, n)==-1) {//递归返回1 说明该位置符合 map[index][i]='\0'; } } } return -1;//递归失败,返回上一级 } } public boolean isOk(int x,int y,char[][] map) {//判断某个点 是否可以安放 int len=map.length; for(int i=y-1,j=1;i>=0;i--) { if(map[i

动态规划 :树塔问题

匿名 (未验证) 提交于 2019-12-02 23:26:52
5 8 3 12 7 16 4 10 11 6 9 5 3 9 4 第一层有一个数字,第二层有2个数字,第n层有n个数字,现在要从第一层走到第n层,每次只能走向下一层连接的两个数字中的一个,问:最后将路径上的所有数字相加得到的和最大是多少? 思路:穷尽的时间复杂度为 O(2 ^ n) ,数大的时候肯定不行,贪心的话,从上往下,每一次都选最大的,只能保证当前是最大的,即子问题满足,但是最后却不满足,当前最大的路线不一定最后是最大的,再看枚举,枚举之所以复杂度大是因为重复的太多了,比如你按5->8->7的路线走,然后再按5->3->7的路线走,还要再走一遍关于7 的路线,所以如果能记录当前的最大值就可以省去很多时间和空间, 具体做法: dp[i][j]=max(dp[i+1][j] + dp[i+1][j+1]) + f[i][j] dp[i][j]称为问题的状态,上面的式子称为状态转移方程 dp[i][j]是当前节点最大的和值,因为每个节点都有两个子节点,所以比较下面的2个节点看哪个大再加上当前他自己本身的值,然后每次循环判断最后dp[1][1] 就能求出最大值; 这个问题最关键的是自底向上的递推写法 自底向上 就表明最底下是边界,边界的节点的dp值就等于他自己本身 #include <iostream> #include <cstdio> using namespace std ;