• 一本通1268:【例9.12】完全背包问题(浅谈完全背包问题)


    原题传送门

    一道完全背包问题模板题,和01背包问题一样,还是拥有两种思路

    (Solution 1)

    依然是一个朴实无华的二维数组

    状态的表示:(f[i][j])表示前(i)个总重量不超过(j)的最大价值

    状态的转移:(f[i][j]=max(f[i-1][j],f[i][j-w[i]]+c[i]) (w[i]<=j))
    注:(w[i])表示第(i)个物品的重量,(c[i])表示第(i)个物品的价值,(j)表示当前的最大重量

    最优解:(f[n][m])
    注:(n)指物体数量,(m)指最大重量

    (Code)

    #include<iostream>
    #include<cstdio>
    #include<string>
    using namespace std;
    inline void read(int &x){
    	int f=1;
    	char ch=getchar();
    	x=0;
    	while(ch<'0'||ch>'9'){
    		if(ch=='-') f=-1;
    		ch=getchar();
    	}
    	while(ch>='0'&&ch<='9'){
    		x=x*10+ch-'0';
    		ch=getchar();
    	}
    	x*=f;
    }
    int m,n;
    int w[31],c[31];
    int f[201][201];
    int main(){
    	read(m);read(n);
    	for(int i=1;i<=n;i++){
    		read(w[i]);
    		read(c[i]);
    	}
    	for(int i=1;i<=n;i++){
    		for(int j=1;j<=m;j++){
    			if(j<w[i]) f[i][j]=f[i-1][j];
    			else f[i][j]=max(f[i-1][j],f[i][j-w[i]]+c[i]); 
    		}
    	}
    	printf("max=%d",f[n][m]);      //"max="是题目中的输出格式要求
    	return 0;
    }
    

    (Solution 2)

    依然可以用一维数组来进行空间优化

    状态的表示:(f[i])表示不超过(i)重量的最大价值

    状态的转移:(f[j]=max(f[j],f[j-w[i]]+c[i]))
    注:(w[i])表示第i个物品的重量,(c[i])表示第i个物品的价值,(j)表示当前的最大重量

    最优解:(f[m])
    注:(m)指最大重量

    (Code)

    #include<iostream>
    #include<cstdio>
    #include<string>
    using namespace std;
    inline void read(int &x){
    	int f=1;
    	char ch=getchar();
    	x=0;
    	while(ch<'0'||ch>'9'){
    		if(ch=='-') f=-1;
    		ch=getchar();
    	}
    	while(ch>='0'&&ch<='9'){
    		x=x*10+ch-'0';
    		ch=getchar();
    	}
    	x*=f;
    }
    int m,n;
    int w[31],c[31];
    int f[201];
    int main(){
    	read(m);read(n);
    	for(int i=1;i<=n;i++){
    		read(w[i]);
    		read(c[i]);
    	}
    	for(int i=1;i<=n;i++){
    		for(int j=w[i];j<=m;j++){
    			f[j]=max(f[j],f[j-w[i]]+c[i]);
    		}
    	}
    	printf("max=%d",f[m]);      //"max="是题目中的输出格式要求
    	return 0;
    }
    

    这里和(01)背包唯一不同的是,内层循环变成了这个:

    for(int j=1;j<=m;j++)
    

    和这个

    for(int j=w[i];j<=m;j++)
    

    (01)背包里,(j)是从最大重量(m)进行倒序遍历到(w[i])的。而这里,是从(w[i])正序遍历到最大重量(m)
    这便是(01)背包和完全背包在一维数组实现上的唯一不同之处
    原因还是来源于本质区别:

    • (01)背包是只有选和不选两个子问题
    • 完全背包是有选和不选两个子问题,但是选里边还有选几个的若干子问题

    所以说,考虑“再选一个第(i)种物品”的方案时,有可能已经选过一个第(i)件物品,当前行的(f[j])需要用到前面的的结果。

    即由于一个物品可以被选择多次,更新(f[i][j])时,(f[i][j-w[i]])可能因为放入物品i而发生变化。所以说需要正序循环。

  • 相关阅读:
    《程序员你伤不起》读书总结
    03SpringBoot用JdbcTemplates访问Mysql
    02Spring Boot配置文件详解
    01构建第一个SpringBoot工程
    java基础-04泛型
    java集合-HashSet源码解析
    java集合-HashMap源码解析
    java基础-03基本语法
    java基础-02数据类型
    java基础-01基本概念
  • 原文地址:https://www.cnblogs.com/-pwl/p/13731583.html
Copyright © 2020-2023  润新知