zoukankan      html  css  js  c++  java
  • 背包问题

    背包问题

    来源

    完全基于中山纪念中学 宋新波ppt的一次复习

    动态规划的关键点

    • 最优化原理

    子问题最优化结构

    • 无后效性

    未来与过去无关

    • 状态

    描述最优解的结构

    • 状态转移方程

    递归定义最优解的值

    • 程序实现

    用记忆化搜索或迭代法求解

    No.1:01背包

    问题

    有N种物品和一个容量为V的背包。
    第i种物品只有1个,体积是v[i],价值是w[i]。
    选择物品装入背包使这些物品的体积总和不超过背包容量,且价值总和最大,求出这个最大价值。

    分析

    • 状态

      (f[i,j])表示用体积为j的背包装前i个物品能获得的最大价值。考虑第i种物品装或不装进行状态转移:

      (f[i-1,j-v[i]]+w[i])(必须满足(j>=v[i]))

      • 不装

      (f[i-1,j])

      • 两种情况取较大值。
    • 状态转移方程为:

    [f[i,j]=left{ egin{array}{rcl} 0 & &{i=0(边界条件)}\ f[i-1,j] & &{j<v[i]}\ max(f[i-1,j],f[i-1,j-v[i]]+w[i])& &{j>=v[i]}\ end{array} ight. ]

    • 答案为(f[n,v]),时间复杂度为(O(N*V))

    code

    #include <bits/stdc++.h> 
    using namespace std;
    
    const int Max=1e4+10;
    int w[Max],v[Max];
    int f[Max][Max]={0};
    
    int main()
    {
    	int n,m;
    	cin>>n>>m;
    	for(int i=1; i<=n; i++)	cin>>v[i];
    	for(int i=1; i<=n; i++)	cin>>w[i];
    	for(int i=1; i<=n; i++)
    		for(int j=0; j<=m; j++)
    			if(j<v[i])	f[i][j]=f[i-1][j];
    			else	f[i][j]=max(f[i-1][j],f[i-1][j-v[i]]+w[i]);
    	cout<<f[n][m]<<endl;
    	return 0;
    }
    

    No.2:完全背包

    问题

    有N种物品和一个容量为V的背包。
    第i种物品有无穷个,体积是v[i],价值是w[i]。
    选择物品装入背包使这些物品的体积总和不超过背包容量,且价值总和最大,求出这个最大价值。

    分析

    方法一

    • 状态:

    (f[i,j])表示用体积为j的背包装前i个物品能获得的最大价值。
    考虑第(i)个物品装几个来进行状态转移,假设装(x)个,(x)的范围为(0<=x<=j / v[i])

    • 状态转移方程:

    [f[i,j]=left{ egin{array}{rcl} 0 & &{i=0(边界条件)}\ max{f[i-1,j-x*v[i]]+x*w[i]}& &{0<=x<=j / v[i]}\ end{array} ight. ]

    • 答案为(f[n,v]),时间复杂度为(O(V^2*displaystyle sum^N_{i=1}{frac1{v[i]}}))

    code

    #include <bits/stdc++.h> 
    using namespace std;
    
    const int Max=1e4+10;
    int w[Max],v[Max];
    int f[Max][Max]={0};
    
    int main()
    {
    	int n,m;
    	cin>>n>>m;
    	for(int i=1; i<=n; i++)	cin>>v[i];
    	for(int i=1; i<=n; i++)	cin>>w[i];
    	for(int i=1; i<=n; i++)
    		for(int j=0; j<=m; j++)
    			for(int x=0; x<=j/v[i]; x++)
    				f[i][j]=max(f[i][j],f[i-1][j-x*v[i]]+x*w[i]);
    	cout<<f[n][m]<<endl;
    	return 0;
    }
    

    方法二

    • 状态

    (f[i,j])表示用体积为j的背包装前(i)个物品能获得的最大价值。

    • 考虑第(i)个物品装或不装来进行状态转移:
      • 装:

      必须满足(j>=v[i]),由于物品有无穷多个,装一次后后面还可以再装,所以状态为(f[i,j-v[i]]+w[i]);

      • 不装:

      (f[i-1,j])

    • 状态转移方程:

    [f[i,j]=left{ egin{array}{rcl} 0 & &{i=0(边界条件)}\ f[i-1,j] & &{j<v[i]}\ max(f[i-1,j],f[i,j-v[i]]+w[i]) & &{j>=v[i]}\ end{array} ight. ]

    • 答案为(f[n,v]),时间复杂度为(O(N*V))

    code

    #include <bits/stdc++.h> 
    using namespace std;
    
    const int Max=1e4+10;
    int w[Max],v[Max];
    int f[Max][Max]={0};
    
    int main()
    {
    	int n,m;
    	cin>>n>>m;
    	for(int i=1; i<=n; i++)	cin>>v[i];
    	for(int i=1; i<=n; i++)	cin>>w[i];
    	for(int i=1; i<=n; i++)
    		for(int j=0; j<=m; j++)
    			if(j<v[i])	f[i][j]=f[i-1][j];
    			else	f[i][j]=max(f[i-1][j],f[i][j-v[i]]+w[i]);
    	cout<<f[n][m]<<endl;
    	return 0;
    }
    

    No.3:多重背包(未完待续)

  • 相关阅读:
    Linq to OBJECT延时标准查询操作符
    LINQ to XML
    动态Linq(结合反射)
    HDU 1242 dFS 找目标最短路
    HDu1241 DFS搜索
    hdu 1224 最长路
    BOJ 2773 第K个与m互质的数
    ZOJ 2562 反素数
    2016 ccpc 杭州赛区的总结
    bfs UESTC 381 Knight and Rook
  • 原文地址:https://www.cnblogs.com/vasairg/p/12385336.html
Copyright © 2011-2022 走看看