动态规划

NOI 2.6 动态规划 9270:Pku2440 DNA

匿名 (未验证) 提交于 2019-12-03 00:22:01
题目来源: http://noi.openjudge.cn/ch0206/9270/ 9270:Pku2440 DNA 总时间限制 单个测试点时间限制 内存限制 描述 输入 The input contains several test cases.For each test case it contains a positive integer L (1 <= L <= 10 ^ 6).The end of input is indicated by end-of-file. 输出 For each test case, output K mod 2005,here K is the number of lives that will not be affected. 样例输入 4 样例输出 9 ----------------------------------------------------- 解题思路 对L 做动态规划。用4个int分别表示以00/01/10/11结尾的长度为i的DNA序列,找到i和i+1之间的递推关系即可。 ----------------------------------------------------- 代码 //9270:Pku2440 DNA //总时间限制: 4000ms 单个测试点时间限制: 1000ms 内存限制: 131072kB

动态规划(dp)

匿名 (未验证) 提交于 2019-12-03 00:22:01
动态规划可以用递归实现,用递归实现会比较简单,就是找递归出口比较难,能找到递归的规律,那用循环就肯定能做了,dp和贪心算法还是有区别的,用递归有可能会重复算一个数,斐波那契就是一个例子,循环会把它记录下来,所以复杂度会比较小。 一:理解dp 就是选最大的数是多少,但是同一时间不能选; 二:简单题理解 就是选出和最大的数是多少,但是相邻的不能选,dp是从后往前分析,找出规律,然后写递归出口,转换成数组, 递归代码: #include<bits/stdc++.h> using namespace std; int rec_opt(int arr[],int len) { if(len==0) return arr[0]; else if(len==1) return max(arr[0],arr[1]); else { int a=rec_opt(arr,len-1);//注意传参数的时候和主函数一样,len是控制下标 int b=rec_opt(arr,len-2)+arr[len]; return max(a,b); } } int main() { int arr[7]={1,2,4,1,7,8,3}; cout<<rec_opt(arr,6)<<endl;//求的是下标为六前的和为最大值的数 return 0; } 数组实现: #include<bits/stdc++.h>

动态规划 矩阵乘法

匿名 (未验证) 提交于 2019-12-03 00:21:02
http://lx.lanqiao.cn/problem.page?gpid=T417 dp[i][j]的含义:从第i个矩阵到第j个矩阵的最优解 动态规划状态方程: 这个题和合并石子很相似,这个题应该是默认了每一个矩阵只能和左右两个矩阵相乘,每次矩阵乘法的最后都是两个矩阵的相乘,要求从矩阵i到矩阵j的相乘的最小值 ,就要比较(j-i)次得到最小值。 #include <iostream> #include <cstdio> #include <algorithm> using namespace std; typedef long long ll; const ll maxn = 1001; const ll inf = INT_MAX; ll dp[maxn][maxn]; ll a[maxn]; ll n; int main(){ cin>>n; for(ll i = 0;i <=n;i++) cin>>a[i]; //默认为第i个矩阵的大小为 a[i-1]*a[i], for(ll i = 1 ; i <= n;i++) for(ll j = 1;j <= n;j++){ if(i == j) dp[i][j] = 0; // i == j 就是只有一个矩阵,dp[i][j]就是0 else dp[i][j] = inf; //初始化为最大值 } for(ll j = 2;j

动态规划与0-1背包问题解析

匿名 (未验证) 提交于 2019-12-03 00:19:01
动态规划,作为程序员面试过程中几乎是必考的题目类型,在实际生产应用中也广泛使用。0-1背包问题作为最经典的算法之一,也衍生了很多其他的题目(如找零钱、爬楼梯等leetcode题目)。本人在复习之余,将总结下来的算法常识得以分享: (一)什么是动态规划 作为运筹学的一个分支,动态规划(DP)最早是用于求解决策过程最优化的问题被提出,利用各阶段dp变量之间的关系,逐个求解,最终求得全局最优解的过程。再设计DP算法时,需确认原问题与子问题的解状态,每个状态下的DP值、边界状态值,以及状态转移方程。 此外,不同于分治策略,DP 划分的子问题是有重叠的,解过程中对于重叠的部分只要求解一次,记录下结果,其他子问题直接使用即可,减少了重复计算过程。 另外,DP在求解一个问题最优解的时候,不是固定的计算合并某些子问题的解,而是根据各子问题的解的情况选择其中最优的。即第i个状态的DP值dp[i]可能前i-1个状态( dp[1]、dp[2]、・・・・・・、dp[i-1] )都相关。 (2)子问题重叠性质:先计算子问题的解,再由子问题的解去构造问题的解(由于子问题存在重叠,把子问题解记录下来为下一步使用)。 (二)0-1背包求解思路 ④、确定状态转移方程,如何从一个或多个已知状态求出另一个未知状态的值。(递推型) (三)算法设计   初始状态为dp[0][0]~ dp[0][ V]和 dp[0][0]~

动态规划问题之求组合数

匿名 (未验证) 提交于 2019-12-03 00:19:01
我们知道,组合数在组合数学中非常有用,组合数是一个十分常用的数字。 比如,书架上有4本书ABCD,我们想拿2本读,那么有C(4,2)种方法。 这个数字的求法是:4!/2!(4-2)!,其中n!=1*2*3...n,是阶乘数。 所以按定义求其实也十分“容易”,这里是指容易写罢了。 先求一个阶乘: def fac(n): if n<=1: return 1 s=1 while n>1: s*=n n-=1 return s 然后求组合数Cnm: def Cnm(n,m): if n<0 or m <0 or n<m: raise ValueError return fac(n)//(fac(m)*fac(n-m)) 真的是非常容易理解了。 数字小,还好说。但如果你不用python,你的阶乘算法很可能溢出,(或者一些新手用递归写阶乘,python是不能高阶递归的,大概990+次递归),那么这个就很麻烦了。 实际上高中老师教的计算方法是,C(n,k)=n*(n-1)...(n-k)/k*(k-1)...1; 原则上是简化了“手算”。 但是不能根本上保证阶乘溢出问题。 苦苦思索,高中真的白读了吗? 其实真的不是,有一种结合了高中一道经典组合题产生的动态规划法可以相对较快的求出组合数,只是多花了不少空间。 考虑: 一个4X5的方格组,也就是一行5个格子,有4行,最开始你站在最左上角

常见算法 - 将给定整数分解成多个和为其的数,求乘积最大的一组数

匿名 (未验证) 提交于 2019-12-03 00:18:01
给定一个数可以分割成多组和等于它的数组,求这样数组中乘积最大的一组(leetcode343) For example, given n = 2, return 1 (2 = 1 + 1); given n = 10, return 36 (10 = 3 + 3 + 4). Note : You may assume that n is not less than 2 and not larger than 58. 思路:动态规划的练习题。对于n这个数的f(n ),即是求1*f(n-1),2*f(n-2)......等中最大的一种情况,可见其适用与动态规划(具有重叠子问题和最优子结构)。对应的可以先用递归,记忆化搜索解题,再到动态规划。 递归记忆化搜索 class Solution { int [] memo ; public int helper ( int n ) { if ( n == 1 ){ return 1 ; } if ( memo [ n ] != 0 ){ return memo [ n ]; } int res = 0 ; for ( int i = 1 ; i < n ; i ++){ res = Math . max ( res , Math . max ( i *( n - i ), i * helper ( n - i ))); } memo [ n ]

背包问题c++动态规划方式

匿名 (未验证) 提交于 2019-12-03 00:16:01
#include <iostream> using namespace std; int weight[5] = {5,2,4,8,6}; int len[5] = {2,4,3,1,7}; int num = 5; int space = 15; int main() { int max_weight[15] = {0}; for(uint32_t i=0; i<num;i++) { for(uint32_t j=space; j>len[i]; j--) { if (max_weight[j-len[i]] + weight[i] > max_weight[j]) { max_weight[j] = max_weight[j-len[i]] + weight[i]; } } for(uint32_t j=0; j<space; j++) { cout<<max_weight[j]<<" "; } cout<<endl; } cout<<max_weight[14]<<endl; return 0; }   结果 0 0 0 5 5 5 5 5 5 5 5 5 5 5 5 0 0 0 5 5 5 5 7 7 7 7 7 7 7 7 0 0 0 5 5 5 9 9 9 9 11 11 11 11 11 0 0 8 8 13 13 13 17 17 17 17 19 19 19 19

矩阵连乘――动态规划

匿名 (未验证) 提交于 2019-12-03 00:15:02
#include<bits/stdc++.h> #define maxn 105 using namespace std; int n,p[1000];//每个矩阵的行数和列数 int m[100][100];//存储最优子结构 int s[100][100];//存储当前结构的最优断点 void MatrixChain() { for(int i=1; i<=n; i++) { //初始化主对角线为0,矩阵链长度为1 m[i][i] = 0; } for(int r=2; r<=n; r++) { //依次计算第r条对角线 for(int i=1; i<=n-r+1; i++) { //每条对角线 的长度 int j = i+r-1; //对角线上每个元素的下标,i行j列 m[i][j] = m[i][i]+m[i+1][j] +p[i-1]*p[i]*p[j],s[i][j] = i; for(int k=i+1;k<j;k++){ //枚举计算m[i][j]的最优解 int t = m[i][k] + m[k+1][j] + p[i-1]*p[k]*p[j]; if(t<m[i][j]){ m[i][j] = t; s[i][j] = k; } } } } } void Traceback(int i,int j){ if(i==j){ return; } Traceback

最小m子段和(动态规划)

匿名 (未验证) 提交于 2019-12-03 00:15:02
给定n个整数组成的序列,现在要求将序列分割为m段,每段子序列中的数在原序列中连续排列。如何分割才能使这m段子序列的和的最大值达到最小? 输入格式: 第一行给出n,m,表示有n个数分成m段,随后一行给出n个数,以空格分隔 输入样例: 9 3 9 8 7 6 5 4 3 2 1 输出样例: 17 解释: 9 8 | 7 6 | 5 4 3 2 1,9个数分成3段所有情况里这种分法的最大子段和(17)最小。 思路: 动态规划的一种模板,包括矩阵连乘,石子归并等问题。先是考虑分的段数,然后考虑起点/终点,最后是每段中分割点的位置。 本题中使用 dp[i][j]表示前i个数分成j段里最小的最大子段和,则dp[i][j]=min{dp[i][1]-dp[k][1],dp[k][j-1] (1<=k<i)}; 代码: #include<bits/stdc++.h> using namespace std; #define N 99 #define inf 0x3f3f3f3f int a[N],dp[N][N];//dp[i][j]表示前i个数分j段所有情况里最大子段和最小的 int main() { int n,m; cin>>n>>m; for(int i=1; i<=n; i++) cin>>a[i]; for(int i=1; i<=n; i++) dp[i][1]=dp[i-1][1]

动态规划-划分数组的最大和 Split Array Largest Sum

匿名 (未验证) 提交于 2019-12-03 00:14:01
2019-10-14 22:13:18 问题描述 : 问题求解 : 经典的动态规划问题。 public int splitArray ( int [] nums , int m ) { int n = nums . length ; long [][] dp = new long [ m + 1 ][ n ]; long [] presum = new long [ n ]; long curSum = 0 ; for ( int i = 0 ; i < n ; i ++) { curSum += nums [ i ]; presum [ i ] = curSum ; dp [ 1 ][ i ] = curSum ; } for ( int i = 2 ; i <= m ; i ++) { for ( int j = 0 ; j < n ; j ++) { dp [ i ][ j ] = curSum ; for ( int k = 0 ; k < j ; k ++) { dp [ i ][ j ] = Math . min ( dp [ i ][ j ], Math . max ( dp [ i - 1 ][ k ], presum [ j ] - presum [ k ])); } } } return ( int ) dp [ m ][ n - 1 ]; }    来源