动态规划和01背包

    技术2022-07-20  86

    动态规划:对解最优问题的一种途径、一种方法,而不是一种特殊算法

    动态规划

    模型01背包

    模型

    经典例题:数字金字塔 题意:金字塔第一层有1个含数字的点,第二层有两个含数字的点……第n层有n个含数字的点,求从n层的任意一点还是,到达第一层所经过的数字和最大为几?例如下图,n=3。 样例输入: 3 12 25 19 6 10 3 很明显,这是道dp水题

    我们先定义一个二维数组dp[][]和a[][],dp[i][j]表示从dp[1][1]到dp[i][j]的最大数字和,a[i][j]存储各个位置上的数值。 并且规定从(1,1)开始,只能向左下或者右下运动。 注意的几点: 1.左下:最后一步为从(i-1,j)走到(i,j),得出规律:如果向左下走,dp[i][j]=dp[i-1][j]+a[i][j]2.右下:最后一步为从(i-1,j-1)走到(i,j),得出规律:如果向右下走,dp[i][j]=dp[i-1][j-1]+a[i][j]3.很明显dp[i][j]需要一个值,根据定义,我们将a[i][j]赋给dp[i][j]

    注意1和2图例:

    ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ 从(1,1)走到左下角的(2,1),也就是从(i-1,j)(i,j)(1,1)走到右下角的(2,2),也就是从(i-1,j-1)(i,j)

    代码:

    #include <cstdio> #include <algorithm> //#include <bits/stdc++.h> using namespace std; int a[1005][1005],dp[1005][1005],n;//数组开多大根据题目来 int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { for(int j=1;j<=i;j++) { scanf("%d",&a[i][j]); } } dp[1][1]=a[1][1];//!注意! for(int i=2;i<=n;i++) { for(int j=1;j<=i;j++) { dp[i][j]=max(dp[i-1][j],dp[i-1][j-1])+a[i][j]; } } int x=0; /* 因为最后的数值存在dp[n][]里面,所以需要一个变量求出最大的数据 */ for(int i=1;i<=n;i++) { x=max(x,dp[n][i]); } printf("%d",x); return 0; } //结束

    这就是动态规划的基本题,dp数塔,最经典的dp。 其他更难的dp题目,详见洛谷题库

    01背包

    背包的基本:01背包

    题目描述(这是我们老师上课给我们的奇葩描述) 你是一名小偷,现在你要去商店里偷东西(好孩子不能偷东西~) 因为动作匆忙,你只带了一个容量为V公斤的背包 商店里有m个商品,每件商品的价值为c[i],重量为v[i]。 求背包最多能装的物品的价值最大是多少? 输入:第一行输入V和n,第2~n+1行,每行输入c[i]和v[i] 输出:之前说过 样例输入: 4 10 1 2 3 3 5 4 9 7 样例输出: 12 思路: 变量dp[][]的用法与数塔类似,不再赘述。 现在我们来想一下第i件物品的情况。第i件物品有“放”和“不放”两种情况。 假如“不放”,问题便和第i件物品无关,只和前i-1件物品有关 假如“放”,那么背包容积至少会变成“V-v[i]”。 此时的最大价值那就很容易得出:dp[i][j]=dp[i-1][j-v[i]]+…… 根据之前动态规划的方法可知,省略号处应该填"a[i][j]"也就是这里的“c[i]” 至于为什么是i-1……动规里已经讲得很清楚了。

    上面的方法是用二维数组做的,那么,能不能用一位数组做呢??? 答案是肯定的

    二维数组的思路肯定需要一重循环是这样的:dp[i][0……V],但可以优化,使循环后的dp[v]就是原本的dp[i][v]。 很容易想明白,我们只要让V从V到0循环,问题就迎刃而解

    CODE

    //一位数组做法 #include <bits/stdc++.h> using namespace std; int main() { //freopen("in2.txt","r",stdin); //freopen("out2.txt","w",stdout); int n,V,c[101],v[101],dp[500]={0}; scanf("%d%d",&n,&V); for(int i=1;i<=n;i++) { scanf("%d%d",&c[i],&v[i]); } for(int i=1;i<=n;i++) { for(int j=V;j>=v[i];j--) { dp[j]=max(dp[j],dp[j-v[i]]+c[i]); } } printf("%d",dp[V]); }

    结束 END

    Processed: 0.008, SQL: 9