动态规划-闫氏老方!中华老字号(DP笔记)

这篇具有很好参考价值的文章主要介绍了动态规划-闫氏老方!中华老字号(DP笔记)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

b站视频
💡 Tips:求有限集中的最值
动态规划-闫氏老方!中华老字号(DP笔记),算法,c++,动态规划

01背包

动态规划-闫氏老方!中华老字号(DP笔记),算法,c++,动态规划

朴素写法

#include <iostream>

using namespace std;

const int N = 1010;

int n, m;
int v[N], w[N];
int f[N][N];

int main()
{
    cin >> n >> m;

    for (int i = 1; i <= n; i ++ ) cin >> v[i] >> w[i];

    for (int i = 1; i <= n; i ++ ){
        for (int j = 0; j <= m; j ++ )
            {
                f[i][j] = f[i - 1][j];  // 左半边的子集
                if (j >= v[i]) 
                    f[i][j] = max(f[i][j], f[i - 1][j - v[i]] + w[i]);
            }
    }
    cout << f[n][m] << endl;

    return 0;
}

作者:yxc
链接:https://www.acwing.com/activity/content/code/content/249968/
来源:AcWing

优化空间之后的写法

怎么说呢,就是原来第二个算式是f[i][j] = max(f[i][j], f[i - 1][j - v[i]] + w[i]),注意f[i - 1][j - v[i]],需要i-1,也就是前一个。
要是从左往右边算的话,✨(假如我们来到了第四行,正在计算f[5]需要用到f[4]的数据),f[4]会先于f[5]的数据被更新,也就是f[5]中存的还是第3行的数据,而f[4]中已经是第4行的数据,所以不满足f[i - 1][j - v[i]]中的i-1。
要是从右往左边算的话,✨(假如我们来到了第四行,正在计算f[5]需要用到f[4]的数据),f[5]会先于f[4]的数据被更新,f[4]中依然是第3行的数据,此时f[5]可以通过f[4](第3行的数据)计算,满足f[i - 1][j - v[i]]中的i-1。
😘下面的完全背包的优化也是如此

#include <iostream>

using namespace std;

const int N = 1010;

int n, m;
int v[N], w[N];
int f[N];

int main()
{
    cin >> n >> m;

    for (int i = 1; i <= n; i ++ ) cin >> v[i] >> w[i];

    for (int i = 1; i <= n; i ++ )
        for (int j = m; j >= v[i]; j -- )
            f[j] = max(f[j], f[j - v[i]] + w[i]);
    //当你从小到大枚举j时,f[ j - v[i] ] 会在f[ j ] 之前被枚举到,,而从大到小枚举j时,在此枚举后,f[ j - v[i] ] 从原来的f[i-1][j-v[i]] 更新成了f[i][j-v[i]],,f[j]一定会先与f[j-v[i]]枚举到,此时f[j-v[i]]依旧是f[i-1][j-v[i]]

    cout << f[m] << endl;

    return 0;
}

作者:yxc
链接:https://www.acwing.com/activity/content/code/content/249968/
来源:AcWing

完全背包

动态规划-闫氏老方!中华老字号(DP笔记),算法,c++,动态规划

💡 Tips:推导公式
f ( i , j ) = m a x ( f ( i − 1 , j ) , f ( i − 1 , j − v i ) + w i , f ( i − 1 , j − 2 v i ) + 2 w i , . . . . . . ) f ( i , j − v i ) = m a x ( f ( i − 1 , j − v i ) , f ( i − 1 , j − 2 v i ) + w i , f ( i − 1 , j − 3 v i ) + 2 w i , . . . . . . ) f ( i , j ) = m a x ( f ( i − 1 , j ) , f ( i , j − v i ) + w i ) f(i,j)=max(f(i-1,j),f(i-1,j-v_i)+w_i,f(i-1,j-2v_i)+2w_i,......)\\ f(i,j-v_i)=max(f(i-1,j-v_i),f(i-1,j-2v_i)+w_i,f(i-1,j-3v_i)+2w_i,......)\\ f(i,j)=max(f(i-1,j),f(i,j-v_i)+w_i) f(i,j)=max(f(i1,j)f(i1,jvi)+wif(i1,j2vi)+2wi......)f(i,jvi)=max(f(i1,jvi)f(i1,j2vi)+wif(i1,j3vi)+2wi......)f(i,j)=max(f(i1,j)f(i,jvi)+wi)

朴素写法

#include <iostream>

using namespace std;

const int N = 1010;

int n, m;
int v[N], w[N];
int f[N][N];

int main()
{
    cin >> n >> m;

    for (int i = 1; i <= n; i ++ ) cin >> v[i] >> w[i];

    for (int i = 1; i <= n; i ++ )
        for (int j = 1; j <= m; j ++ )
        {
            f[i][j] = f[i - 1][j];
            //f[j] = f[j];先算右边,是上一层的
            if (j >= v[i]) 
                f[i][j] = max(f[i][j], f[i][j - v[i]] + w[i]);
            //f[j] = max(f[j], f[j - v[i]] + w[i]);
            //在算f[j]的时候,f[j - v[i]]已经被算出来了,就是第i层的
        }

    cout << f[n][m] << endl;

    return 0;
}

作者:yxc
链接:https://www.acwing.com/activity/content/code/content/250029/
来源:AcWing

优化空间之后的写法

#include <iostream>

using namespace std;

const int N = 1010;

int n, m;
int v[N], w[N];
int f[N];

int main()
{
    cin >> n >> m;

    for (int i = 1; i <= n; i ++ ) cin >> v[i] >> w[i];

    for (int i = 1; i <= n; i ++ )
        for (int j = v[i]; j <= m; j ++ )
            f[j] = max(f[j], f[j - v[i]] + w[i]);

    cout << f[m] << endl;

    return 0;
}

作者:yxc
链接:https://www.acwing.com/activity/content/code/content/250029/
来源:AcWing

对比

//01背包
f[i][j] = max(f[i][j], f[i - 1][j - v[i]] + w[i]);
//完全背包
f[i][j] = max(f[i][j], f[i][j - v[i]] + w[i]);

区间DP问题

设有N堆石子排成一排,其编号为1,2,3,…,N。每堆石子有一定的质量,可以用一个整数来描述,现在要将这N堆石子合并成为一堆。每次只能合并相邻的两堆,合并的代价为这两堆石子的质量之和,合并后与这两堆石子相邻的石子将和新堆相邻合并时由于选择的顺序不同,合并的总代价也不相同。
例如有4堆石子分别为 1352,我们可以先合并1、2堆,代价为4,得到4 5 2,又合并 1,2堆,代价为9,得到92,再合并得到11,总代价为4+9+11=24;
如果第二步是先合并2,3堆,则代价为7,得到4 7,最后一次合并代价为11,总代价为4+7+11=22.
问题是:找出一种合理的方法,使总的代价最小,输出最小代价。
输入格式

第一行一个数N表示石子的堆数N。
0第二行N个数,表示每堆石子的质量(均不超过1000)。

输出格式

输出一个整数,表示最小代价。

数据范围

1 <N < 300

输入样例

4
1 3 5 2

输出样例

2

动态规划-闫氏老方!中华老字号(DP笔记),算法,c++,动态规划

#include <iostream>

using namespace std;

const int N = 310;

int n;
int s[N];  // 前缀和
int f[N][N];

int main()
{
    cin >> n;
    for (int i = 1; i <= n; i ++ ) cin >> s[i], s[i] += s[i - 1];

    for (int len = 2; len <= n; len ++ )//区间长度
        for (int i = 1; i + len - 1 <= n; i ++ )//左端点
        {
            int j = i + len - 1;//右端点
            f[i][j] = 1e8;
            for (int k = i; k < j; k ++ )
                f[i][j] = min(f[i][j], f[i][k] + f[k + 1][j] + s[j] - s[i - 1]);
        }

    cout << f[1][n] << endl;

    return 0;
}

作者:yxc
链接:https://www.acwing.com/activity/content/code/content/250070/
来源:AcWing

前缀和

一维前缀和:有一个一维数组 x 和该数组的一维前缀和数组 y ,则 x 和 y 满足以下关系:
y 0 = x 0 、 y 1 = x 0 + x 1 、 y 2 = x 0 + x 1 + x 2 、 … … y n = x 0 + x 1 + x 2 + … + x n y_0=x_0、y_1=x_0+x_1、y_2=x_0+x_1+x_2、……y_n=x_0+x_1+x_2+…+x_n y0=x0y1=x0+x1y2=x0+x1+x2……yn=x0+x1+x2++xn

s[1] = a[1] ;
s[2] = a[1] + a[2] ;
s[3] = a[1] + al2] +a[3] ;
....
s[i] = a[1] + a[2] + a[3] + ......+ a[i]; 

最长公共子序列

动态规划-闫氏老方!中华老字号(DP笔记),算法,c++,动态规划文章来源地址https://www.toymoban.com/news/detail-861784.html

#include <iostream>

using namespace std;

const int N = 1010;

int n, m;
char a[N], b[N];
int f[N][N];

int main()
{
    cin >> n >> m >> a + 1 >> b + 1;

    for (int i = 1; i <= n; i ++ )
        for (int j = 1; j <= m; j ++ )
        {
            f[i][j] = max(f[i - 1][j], f[i][j - 1]);
            if (a[i] == b[j]) 
                f[i][j] = max(f[i][j], f[i - 1][j - 1] + 1);
        }

    cout << f[n][m] << endl;

    return 0;
}

作者:yxc
链接:https://www.acwing.com/activity/content/code/content/250113/
来源:AcWing

到了这里,关于动态规划-闫氏老方!中华老字号(DP笔记)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 动态规划:线性DP

    2024年02月06日
    浏览(41)
  • 算法——动态规划(DP)——递推

    动态规划常用于解决优化问题。 动态规划通常以自底向上或自顶向下的方式进行求解。 自底向上的动态规划从最简单的子问题开始,逐步解决更复杂的问题,直到达到原始问题。 自顶向下的动态规划则从原始问题出发,分解成子问题,并逐步求解这些子问题。 动态规划算法

    2024年01月20日
    浏览(57)
  • 动态规划入门(DP)

    目录 1.DP概念和编程方法 1.1.DP概念 例如: 1.1.1.重叠子问题 1.1.2.最优子结构 “无后效性” 1.2.DP的两种编程方法 1.2.1.自顶向下与记忆化 1.2.2.自底向上与制表递推 对比两种方法 1.3.DP的设计和实现(0/1背包问题) 例题: Bone collector(hdu 2606) Problem Description Input Output Sample Inpu

    2024年02月19日
    浏览(38)
  • DP算法:动态规划算法

    (1)确定初始状态 (2)确定转移矩阵,得到每个阶段的状态,由上一阶段推到出来 (3)确定边界条件。 蓝桥杯——印章(python实现) 使用dp记录状态,dp[i][j]表示买i张印章,凑齐j种印章的概率 i表示买的印章数,j表示凑齐的印章种数 情况一:如果ij,不可能凑齐印章,概

    2024年02月07日
    浏览(51)
  • ★动态规划(DP算法)详解

    什么是动态规划:动态规划_百度百科 内容太多了不作介绍,重点部分是无后效性,重叠子问题,最优子结构。 问S-P1和S-P2有多少种路径数,毫无疑问可以先从S开始深搜两次,S-P1和S-P2找出所有路径数,但是当这个图足够大,那就会超时。 动态规划旨在用 空间换时间 ,我们

    2024年02月04日
    浏览(50)
  • 动态规划(DP)(算法笔记)

    本文内容基于《算法笔记》和官方配套练题网站“晴问算法”,是我作为小白的学习记录,如有错误还请体谅,可以留下您的宝贵意见,不胜感激。 动态规划(Dynamic Programming,DP)是一种用来解决一类最优化问题的算法思想。简单来说,动态规划将一个复杂的问题分解成若干个子

    2024年02月05日
    浏览(47)
  • 动态规划——线性DP

    暴力搜索:由可行的所有起点出发,搜索出所有的路径。 但是深搜的算法时间复杂度要达到 O ( 2 n ) O(2^n) O ( 2 n ) (每个数都有选或不选的两个选择),指数级的时间复杂度在本题中( n ≤ 100 n≤100 n ≤ 100 )显然是不能接受的。那么再观察这个这棵递归树,可以发现其中有很

    2024年01月19日
    浏览(48)
  • 【dp动态规划】印章

    共有n种图案的印章,每种图案的出现概率相同。小A买了m张印章,求小A集齐n种印章的概率。 一行两个正整数n和m 一个实数P表示答案,保留4位小数。 2 3 0.7500 python代码

    2024年02月02日
    浏览(60)
  • 动态规划-概率DP

    https://www.luogu.com.cn/problem/CF148D 袋子里有 w w w 只白鼠和 b b b 只黑鼠 ,A和B轮流从袋子里抓,谁先抓到白色谁就赢。A每次随机抓一只,B每次随机抓完一只之后会有另一只随机老鼠跑出来。如果两个人都没有抓到白色则B赢。A先抓,问A赢的概率。 输入 一行两个数 w , b w,b w , b 。

    2024年02月08日
    浏览(29)
  • 动态规划【DP】详细解释

    动态规划,英文简称DP,是一种常见的算法设计思想。 它通常被应用于需要求解最优化问题的场景中。其核心思想是将原问题分解成若干个子问题进行求解,并将子问题的解记录下来,避免重复计算。 动态规划的常见四步骤为:定义状态;设计状态转移方程;给定边界条件;

    2024年02月05日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包