动态规划模板总结(1)

动态规划思想(1)


背包问题

​ 分类:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZiRTbMOi-1668940619398)(C:\Users\44110\AppData\Roaming\Typora\typora-user-images\image-20221118190636657.png)]


01 背包问题

  • 含义:每个物体最多选1次,在不超过总体积的情况下价值最大
  • 图解:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iOlFCDpU-1668940619399)(C:\Users\44110\AppData\Roaming\Typora\typora-user-images\image-20221118194320380.png)]

  • f(i,j)表示的是集合的某种属性,是个值。

  • 集合是所有选法

  • i 只从前i个中选

  • 朴素实现

    #include<iostream>
    #include<algorithm>
    
    using namespace std;
    
    const int N = 1010;
    
    int n,m;//n代表物品个数m代表容量
    int v[N],w[M];//v代表体积,w代表价值
    int f[N][N];//全局变量默认为0
    
    int mian(){
    	cin >> n >> m;
    	for(int i = 1; i <= n; i++) cin >> v[i] >> w[i];
    	//for[0][0~m]//考虑0件物品,最大价值不超过0~m  但默认为0所以可以不写
    	for(int i = 1; i <= n; i++)
    		for(int j = 0; j <= m; j++){//j代表体积
    			f[i][j] = f[i-1][j]//代表左边不含i的情况
    			if(j >= v[i])//如果第i件物品体积大于背包就装不下了
    				f[i][j] = max(f[i][j],f[i-1][j-v[i]] + w[i]);
    		}
    		
    		cout << f[n][m] << endl;
    		
    		return 0;
    }
    
    • 一维实现

      
      #include<iostream>
      #include<algorithm>
      
      using namespace std;
      
      const int N = 1010;
      
      int n,m;//n代表物品个数m代表容量
      int v[N],w[M];//v代表体积,w代表价值
      int f[N];//全局变量默认为0
      
      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]);
          cout << f[m] << endl;
          return 0;
      }
      
  • 滚动数组:如果f()只用到了上层的数据,完全可以只用f(2)和f(1)交替来算。不需要创建额外的空间。

  • 一维实现:运用了滚动数组的思想,每次找最大值就是从前面一次的数组寻值,而且由于公式的原因不可能从原地址取值。运用了一维就可以直接把前面i代表的那一维去掉


02完全背包问题

​	[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NsMSQYGG-1668940619400)(C:\Users\44110\AppData\Roaming\Typora\typora-user-images\image-20221119222938423.png)]

  • 朴素实现

    #include<iostream>
    #include<algorithm>
    
    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++)
                for(int k = 0; k*v[i] <= j;k++)
                    f[i][j] = max(f[i][j],f[i-1][j - v[i]*k] + w[i] * k);
        
        cout << f[n][m] << endl;
    
    }
    

    优化思路:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-k1yhjJnh-1668940619400)(C:\Users\44110\AppData\Roaming\Typora\typora-user-images\image-20221119224101349.png)]

  • 代码

    #include<iostream>
    #include<algorithm>
    
    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][j-v[i]] + w[i])//
            }
        cout << f[n][m] << endl;
    
    }
    

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bnxrobhy-1668940619400)(C:\Users\44110\AppData\Roaming\Typora\typora-user-images\image-20221119225212294.png)]

  • 和01背包问题比较,可以看出还能继续优化
#include<iostream>
#include<algorithm>

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[i][j] = max(f[j],f[j-v[i]] + w[i]);
    cout << f[m] << endl;

}

; i <= n; i++) cin >> v[i] >> w[i];

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

}


- 01背包问题从小到大,完全背包是从大到小。为什么01和完全只差个顺序呢?
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值