ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

背包问题

2021-10-01 18:33:07  阅读:140  来源: 互联网

标签:输出 背包 容量 int cin 问题 物品


01背包

对第i个物品进行决策,选与不选

状态与选择
状态:背包的容量,可选择的物品
选择:选或不选
f[i][j] :前i个物品容量为j的价值最大值

for(n件物品)

for(容量)

if(容量不够)不选
else max(不选i,选i)

模板题 【01背包问题】

有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。

第 i 件物品的体积是 vi,价值是 wi。

求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。

输入格式
第一行两个整数,N,V,用空格隔开,分别表示物品数量和背包容积。

接下来有 N 行,每行两个整数 vi,wi,用空格隔开,分别表示第 i 件物品的体积和价值。

输出格式
输出一个整数,表示最大价值。

数据范围
0<N,V≤1000
0<vi,wi≤1000
输入样例
4 5
1 2
2 4
3 4
4 5
输出样例:
8

    #include<bits/stdc++.h>

    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++ )
    			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;
    }

优化 一维数组

f【j】:n件物品容量为j时的最优解

逆序枚举背包容量,否则f[i-1][j]可能被更新为f[i][j]

    #include<bits/stdc++.h>

    using namespace std;

    const int N = 1010;

    int n, m;
    int f[N];
    int v[N], w[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]);
    	cout<<f[m]<<endl;
    	
    	return 0;
    }

优化输入

可以边输入边处理

    #include<bits/stdc++.h>

    using namespace std;

    const int N = 1010;

    int n, m;
    int f[N];

    int main()
    {
    	cin>>n>>m;
    	for( int i = 1; i <= n; i++ ){
    		int v, w;
    		cin>>v>>w;
    		for( int j = m; j >= v; j-- )
    			f[j] = max(f[j], f[j-v]+w);
    	}
    	cout<<f[m]<<endl;
    	
    	return 0;
    }

完全背包问题

有 N 种物品和一个容量是 V 的背包,每种物品都有无限件可用。

第 i 种物品的体积是 vi,价值是 wi。

求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。

输入格式
第一行两个整数,N,V,用空格隔开,分别表示物品种数和背包容积。

接下来有 N 行,每行两个整数 vi,wi,用空格隔开,分别表示第 i 种物品的体积和价值。

输出格式
输出一个整数,表示最大价值。

数据范围
0<N,V≤1000
0<vi,wi≤1000
输入样例
4 5
1 2
2 4
3 4
4 5
输出样例:
10

集合划分:第i个物品选0个,第i个物品选k个
f[i][j] = max(f[i-1][j], f[i][j-v]+w)

朴素版本

    #include<bits/stdc++.h>

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

优化到一维

    #include<bits/stdc++.h>

    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;
    }

同样优化输入

    #include<bits/stdc++.h>

    using namespace std;

    const int N = 1010;

    int n, m;
    int f[N];

    int main()
    {
    	cin>>n>>m;
    	for( int i = 1; i <= n; i++ ){
    	    int v, w;
    	    cin>>v>>w;
    		for( int j = v; j <= m; j++ )
    			f[j] = max(f[j], f[j-v]+w);
    	}
    	cout<<f[m]<<endl;
    	
    	return 0;
    }

多重背包问题

有 N 种物品和一个容量是 V 的背包。

第 i 种物品最多有 si 件,每件体积是 vi,价值是 wi。

求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。
输出最大价值。

输入格式
第一行两个整数,N,V,用空格隔开,分别表示物品种数和背包容积。

接下来有 N 行,每行三个整数 vi,wi,si,用空格隔开,分别表示第 i 种物品的体积、价值和数量。

输出格式
输出一个整数,表示最大价值。

数据范围
0<N,V≤100
0<vi,wi,si≤100
输入样例
4 5
1 2 3
2 4 1
3 4 3
4 5 2
输出样例:
10

一(当数据范围比较小的时候)

1.可以硬拆成01背包,即把s个相同的物品单独看
cin>>n>>m;
while(n--)
{
cin>>v>>w>>s;
while(s--){
a[++t]=v;//01背包的体积
b[t]=w;//01背包的价值
}
}
for(int i=1;i<=t;i++)
for(int j=m;j>=a[i];j--)
f[j]=max(f[j], f[j-a[i]]+b[i]);

2.三重循环,第三重循环枚举第i个物品从1~s所有的情况

代码如下:

    #include<bits/stdc++.h>

    using namespace std;

    const int N = 110;

    int n, m;
    int f[N];

    int main()
    {
    	cin>>n>>m;
    	for( int i = 1; i <= n; i++ ){
    		int v, w, s;
    		cin>>v>>w>>s;
    		for( int j = m; j >= 0; j-- )
    			for( int k = 1; k <= s && k*v <= j; k++ )
    				f[j] = max(f[j], f[j-k*v]+k*w);
    	}
    	cout<<f[m]<<endl;
    	
    	return 0;
    }

多重背包问题(二进制优化,如果不优化时间复杂度会达到1e9)

正常情况下,一组1024个物品需要枚举1025次,用二进制优化可以<=10次,时间复杂度从O(n^3) -> O(n^2logn)

代码如下
#include<bits/stdc++.h>

    #define x first
    #define y second

    using namespace std;

    typedef pair<int, int> PII;

    const int N = 2010;

    int n, m;
    int f[N];

    int main()
    {
        vector<PII> goods;
        cin>>n>>m;
        for( int i = 1; i <= n; i++ ){
            int v, w, s;
            cin>>v>>w>>s;
            for( int k = 1; k <= s; k*=2 ){
                s-=k;
                goods.push_back({k*v, k*w});
            }
            if(s > 0)
                goods.push_back({s*v, s*w});
        }
        for( auto t:goods){
            for( int j = m; j >= t.x; j-- )
                f[j] = max(f[j], f[j-t.x]+t.y);
        }
        cout<<f[m]<<endl;
        
        return 0;
    }

分组背包问题

有 N 组物品和一个容量是 V 的背包。

每组物品有若干个,同一组内的物品最多只能选一个。
每件物品的体积是 vij,价值是 wij,其中 i 是组号,j 是组内编号。

求解将哪些物品装入背包,可使物品总体积不超过背包容量,且总价值最大。

输出最大价值。

输入格式
第一行有两个整数 N,V,用空格隔开,分别表示物品组数和背包容量。

接下来有 N 组数据:

每组数据第一行有一个整数 Si,表示第 i 个物品组的物品数量;
每组数据接下来有 Si 行,每行有两个整数 vij,wij,用空格隔开,分别表示第 i 个物品组的第 j 个物品的体积和价值;
输出格式
输出一个整数,表示最大价值。

数据范围
0<N,V≤100
0<Si≤100
0<vij,wij≤100
输入样例
3 5
2
1 2
2 4
1
3 4
1
4 5
输出样例:
8

for( int i = 1; i <= n; i++ )

for( int j = m; j >= v; j-- )

f[j] = max(f[j], f[j-v[0]]+w[0], f[j-v[1]]+w[1], ..., f[j-v[s-1]]+w[s-1]);

代码如下:

    #include<bits/stdc++.h>

    using namespace std;

    const int N = 110;

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

    int main()
    {
        cin>>n>>m;
        for( int i = 1; i <= n; i++ ){
            int s;
            cin>>s;
            for( int j = 1; j <= s; j++ )
                cin>>v[j]>>w[j];
            for( int j = m; j >= 0; j-- )
                for( int k = 1; k <= s; k++ )
                    if(j >= v[k])
                        f[j] = max(f[j], f[j-v[k]]+w[k]);
        }
        cout<<f[m]<<endl;
        
        return 0;
    }

标签:输出,背包,容量,int,cin,问题,物品
来源: https://www.cnblogs.com/IntroductionToAlgorithms/p/15358909.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有