动态规划算法

环形石子合并问题(动态规划)(洛谷P1880)

醉酒当歌 提交于 2019-12-02 19:58:30
环形石子合并问题(动态规划) 传统的石子合并问题为:有N堆石子,现要将石子有序的合并成一堆,规定如下:每次只能移动相邻的2堆石子合并,合并花费为新合成的一堆石子的数量,求将这N堆石子合并成一堆的总花费最小(或最大)。 这类问题类似区间DP的解法,设dp[i][j]为合并从i到j的最小总花费,那么预处理出前缀和,转移方程为dp[i][j]=max(dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]),且i==j时dp[i][j]=0;核心代码为: for(int v = 1; v < n; v++) { for(int i = 0;i < n-v; i++) { int j = i + v; dp[i][j] = INF; int tmp = sum[j] - (i > 0 ? sum[i-1]:0); for(int k = i; k < j; k++) dp[i][j] = min(dp[i][j], dp[i][k] + dp[k+1][j] + tmp); } } 环形石子合并问题为洛谷P1880 题目描述 在一个圆形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。 试设计出1个算法,计算出将N堆石子合并成1堆的最小得分和最大得分. 输入输出格式 输入格式:

算法_动态规划_石子合并问题

China☆狼群 提交于 2019-12-02 19:58:17
问题描述: 在一个圆形操场的四周摆放着n 堆石子。现要将石子有次序地合并成一堆。 规定每次只能选相邻的2 堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。 试设计一个算法,计算出将n堆石子合并成一堆的最小得分和最大得分 问题分析: 在此我们假设有n堆石子,一字排开,合并相邻两堆的石子,每合并两堆石子得到一个分数,最终合并后总分数最少的。 我们设m(i,j)定义为第i堆石子到第j堆石子合并后的最少总分数。a(i)为第i堆石子得石子数量。 当合并的石子堆为1堆时,很明显m(i,i)的分数为0; 当合并的石子堆为2堆时,m(i,i+1)的分数为a(i)+a(i+1); 当合并的石子堆为3堆时,m(i,i+2)的分数为 MIN((m(i,i)+m(i+1,i+2)+sum(i,i+2)) (m(i,i+1)+m(i+2,i+2)+sum(i,i+2)); 当合并的石子堆为4堆时…… import java.util.Scanner; public class Main { private static int n; private static int [] arr; private static int [] sum; private static int [][] dp; /** * @param args */ public static void main

leetcode 动态规划整理

被刻印的时光 ゝ 提交于 2019-12-02 09:34:43
动态规划整理 1.最长公共子序列 # 给定两个字符串 text1 和 text2,返回这两个字符串的最长公共子序列。 # # 一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。 # 例如,"ace" 是 "abcde" 的子序列,但 "aec" 不是 "abcde" # 的子序列。两个字符串的「公共子序列」是这两个字符串所共同拥有的子序列。 # # 若这两个字符串没有公共子序列,则返回 0。 # 示例 1: # # 输入:text1 = "abcde", text2 = "ace" # 输出:3 # 解释:最长公共子序列是 "ace",它的长度为 3。 class Solution(object): def longestCommonSubsequence(self, text1, text2): """ :type text1: str :type text2: str :rtype: int """ m,n=len(text1),len(text2) dp=[[0 for _ in range(m+1)] for _ in range(n+1)] for i in range(1,n+1): for j in range(1,m+1): str1=text1[:j] str2

算法笔记-动态规划

随声附和 提交于 2019-12-02 02:30:28
(1)最长公共子序列   说明:假如有一个字符串是abcde。那么他的子序列包括a,ab,bc,ad,abc,abe等等(这个不一定非要连续,只要每个字符取自该字符串并且保持前后顺序就可以)。现在给定两个字符串cnblogs,belong,他们的公共的序列包括bl,bo等等,求其最长的子序列   思路:其最长的子序列是blog。先理解一下书上的给的几个结论:        最后的总结很重要,逻辑就是根据这个来的。   代码: 1 <?php 2 $str1 = 'cnblogs'; 3 $str2 = 'belong'; 4 function findStr($str1, $str2) 5 { 6 if ($str1 == '' || $str2 == '') //i=0或j=0 7 return ''; 8 9 while ($str1 != '' && $str2 != '') 10 { 11 if ($str1[strlen($str1) - 1] == $str2[strlen($str2) - 1]) { //X(i) = Y(j) 12 $res = substr($str1, -1) . $res; 13 list($str1, $str2) = [substr($str1, 0, -1), substr($str2, 0, -1)]; 14 } else { //X

动态规划专题总结

安稳与你 提交于 2019-11-30 22:29:24
  在好早之前做过两篇dp的题目总结,那个时候并没有使用在线刷题工具,可能缺少被认证性。动态规划(Dynamic Progamming)是我最喜欢的分析方法之一,它拥有数学归纳法的优美,又可以解决计算机的问题。当然了,如果从理论角度去总结,我可能还不够格,但是从具体的问题去总结套路,在近两个月的刷题中也逐渐熟练。动态规划有一种,一眼看到问题一头雾水,想通了之后豁然开朗的感觉,就像证明归纳法k=n+1时候的样子。   借九章算法的候老师的总结,动态规划一般分为四个步骤:(1)状态;(2)状态转移方程;(3)初始条件;(4)终止条件    状态 :对于一个可以迭代的问题,他的每一阶的迭代就是一个状态。比如 f(n)是一个问题为n阶的解,f(n)就是一个状态。    状态转移方程 :状态是一个孤立的量,而状态之间的转移使得动态规划是有解的。状态转移方程类似是:f(n)=f(n-1)+f(n-2)这种形式的;之所以动态规划可以使用状态转移方程,是因为它具有重叠子问题并且构造最优子结构以达到全局最优解的特性。    初始条件 :对于一个有状态的系统,它一定要有初态。    终止条件 :同理。   动态规划还有一个特别明显的条件,就是 自顶向下分析问题,自底向上构造解集 。   收集了一波LC的DP题目,由浅入深。 70. Climbing Stairs        这个问题很经典

动态规划与记忆化搜索

£可爱£侵袭症+ 提交于 2019-11-30 16:12:05
同步发表于我的洛谷博客 这里 引入 采药(luogu P1048) 题解 直接写一个粗暴的 DFS : int n,t; int tcost[103],mget[103]; int ans = 0; void dfs( int pos , int tleft , int tans ){ if( tleft < 0 ) return; if( pos == n+1 ){ ans = max(ans,tans); return; } dfs(pos+1,tleft,tans); dfs(pos+1,tleft-tcost[pos],tans+mget[pos]); } int main(){ cin >> t >> n; for(int i = 1;i <= n;i++) cin >> tcost[i] >> mget[i]; dfs(1,t,0); cout << ans << endl; return 0; } \({\color{Red}30}\) 分 尝试优化 不借助任何 "外部变量"(就是 dfs 函数外且 值随 dfs 运行而改变的变量 ), 比如 ans 把 ans 删了之后就有一个问题: 我们拿什么来记录答案? 答案很简单: 返回值! 此时 dfs(pos,tleft) 返回 在时间 tleft 内采集 后 pos 个草药, 能获得的最大收益 不理解就看看代码吧:

【动态规划】最长连号

廉价感情. 提交于 2019-11-30 02:02:18
原题传送门 思路 码风丑丑哒 尽管是一道入门级别的水题,n<10000,暴力就可以过,但若n<100000000,就需要我们伟大的动态规划出场了QAQ。 运用DP,我做出了O(n)的算法。 dp[i]表示从上一个连号被中断的数字的下一个到第i个的连号长度。 有点难理解哈,看状态转移方程吧: dp[i]=dp[i-1]+1(no[i]=no[i-1]+1) dp[i]=1 (no[i]≠no[i-1]+1) (no[]表示输入的数组) 我们还需要一个tans来记录当前连号长度,若tans>ans,则将ans设置为tans,若连号中断,则将tans重置为1。 剩下的就是水代码了QAQ. Code #include<iostream> #include<cstdio> using namespace std; const int MAX=10001; int dp[MAX],no[MAX]; int n,ans=1,tans; int main() { //初始化 dp[1]=1; //freopen("testdata(3).txt","r",stdin); //读入 cin>>n; for(int i=1;i<=n;i++) { cin>>no[i]; } //装叉走起 for(int i=2;i<=n;i++) { if(no[i]==no[i-1]+1) { dp[i]=dp[i

算法理论(一)动态规划

你离开我真会死。 提交于 2019-11-29 17:34:19
一.前言   周末果然是堕落的根源,原谅我两天没刷题(PS:主要是因为周末搬家去了)。上次在这个题的时候,看到网上很多方法都是用动态规划做的,但是本渣渣实在不知道动态规划具体是怎样的,于是就专门花了花时间去研究了一下。肯定没这么快弄懂,只能说是稍微入门,于是写下这篇文章,帮助自己也帮助别人理解动态规划。 二.理论部分   动态规划是什么呢? 百度百科上的定义是:动态规划(dynamic programming)是运筹学的一个分支,是求解决策过程(decision process)最优化的数学方法。用通俗的话来讲,动态规划是针对与 某一类问题 的解决方法。只要我们弄清楚了某一类问题是什么,那我们就知道什么是动态规划。   首先,我们举一个简单的例子,也是dp的入门经典问题:如果我们有面值为1元、5元和11元的纸币若干枚,如何用最少的纸币凑够12元?   按照人类的正常思维来说,首先我们会尽可能的使用大面值的纸币,所以会得出 12 = 11 x 1 + 1 x 1,最少使用两张纸币。这样一看好像这种方法没什么问题,可是当我们把问题换成凑够15元时,继续按照上面这种思路,我们会得到 15 = 11 x 1 + 1 x 4,也就是说,按照惯性思路,我们会认为最少需要五张纸币才能凑齐15元。但是我们可以轻易的看出,15 = 5 x 3,最少只需要三张纸币就能够凑齐15元

Day-09-动态规划 Leetcode-70, 198, 53, 32, 120, 300, 64, 174

房东的猫 提交于 2019-11-29 15:13:12
目录 例一:LeetCode70 例二:LeetCode198 例三:LeetCode53 例四:LeetCode32 例五:LeetCode120 例六:LeetCode300 例七:LeetCode64 例八:LeetCode174 例一:LeetCode70 /** You are climbing a stair case. It takes n steps to reach to the top. Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top? */ #include <stdio.h> #include <vector> class Solution { public: int climbStairs(int n) { std::vector<int> dp(n + 3, 0); // 创建长度为n + 3的数组,初始化为0 dp[1] = 1; dp[2] = 2; for (int i = 3; i <= n; i++) { dp[i] = dp[i - 1] + dp[i - 2]; } return dp[n]; } }; int main() { Solution solve; printf("%d\n",

【算法总结】动态规划 (Dynamic Programming)

試著忘記壹切 提交于 2019-11-29 10:08:50
[算法总结] 动态规划 本文组织结构如下: 前言 最长公共子序列(LCS) 最长不下降子序列(LIS) 最大连续子序列之和 最长回文子串 数塔问题 背包问题(Knapsack-Problem) 矩阵链相乘 总结 前言 在学过的算法当中,DP给我的感觉是最难的了。借着本次写blog好好复习一下这个算法。 众所周知,DP算法的关键点: 抽象出问题的状态表示 定义状态转移方程 填表顺序 最长公共子序列 最长公共子序列(Longest Common Subsequence,LCS),顾名思义,是指在所有的子序列中最长的那一个,子序列要求都出现过并且出现顺序与母串保持一致。 例如,给定字符串 a 和 b : string a = "cnblog" string b = "belong"; blog 都出现过,且字母顺序一致,那就一个公共子序列(在这里也是最长的公共子序列)。 状态定义: dp[i, j] 表示 a[0,...,i] 与 b[0,...j] 的最长公共子序列的长度 那么现在的目的就是求出: dp[alen, blen] 状态转移方程: = 0 if i=0 or j=0 dp[i,j] = dp[i-1,j-1]+1 if a[i]=b[j] = max(dp[i-1,j], dp[i, j-1]) if a[i]!=b[j] 观察可知,每一个 dp[i,j] 都是依赖于