更好的阅读体验
\color{red}{更好的阅读体验}
更好的阅读体验
5.1 模板题
分组背包问题
描述
有 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
思想
- 状态表示:
- 集合:
dp[j]
表示背包体积不超过j
时的价值 - 属性:最大价值
- 集合:
- 状态计算:
- 分组:
v[i][k]
为i
组的第k
个物品的体积,w[i][k]
为i
组的第k
个物品的价值 - 对于每组进行最优决策:
dp[j] = max(dp[j],dp[j - v[i][k]] + w[i][k])
- 分组:
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 110;
int dp[N];
int v[N][N], w[N][N];
void solve(){
int n, m;
cin >> n >>m;
for(int i = 1; i <= n; i ++){
int s[i];
cin >> s[i];
for(int j = 1; j <= s[i]; j ++){
cin >> v[i][j] >> w[i][j];
}
for(int j = m; j >= 0; j --){
for(int k = 1; k <= s[i]; k ++){
if(j >= v[i][k]) dp[j] = max(dp[j],dp[j - v[i][k]] + w[i][k]);
}
}
}
cout << dp[m] << endl;
}
int main(){
solve();
return 0;
}
5.2 提高练习
1013. 机器分配
描述
总公司拥有M台 相同 的高效设备,准备分给下属的N个分公司。
各分公司若获得这些设备,可以为国家提供一定的盈利。盈利与分配的设备数量有关。
问:如何分配这M台设备才能使国家得到的盈利最大?
求出最大盈利值。
分配原则:每个公司有权获得任意数目的设备,但总台数不超过设备数M。
输入格式
第一行有两个数,第一个数是分公司数N,第二个数是设备台数M;
接下来是一个N*M的矩阵,矩阵中的第 i 行第 j 列的整数表示第 i 个公司分配 j 台机器时的盈利。
输出格式
第一行输出最大盈利值;
接下N行,每行有2个数,即分公司编号和该分公司获得设备台数。
答案不唯一,输出任意合法方案即可。
数据范围
1≤N≤10,
1≤M≤15
输入样例:
3 3
30 40 50
20 30 50
20 25 30
输出样例:
70
1 1
2 1
3 1
思想
- 状态表示:
- 集合:
dp[i][j]
表示前i
个公司,使用服务器不超过j
获得的盈利的集合 - 属性:最大盈利
- 集合:
- 状态计算:
- 不选第
i
个公司的服务器:dp[i - 1][j]
- 选择第
i
个公司的k
个服务器:dp[i][j] = dp[i - 1][j - k] + w[i][k]
- 集合属性为最大盈利,取两种方案
max()
:dp[i][j] = max(dp[i - 1][j],dp[i - 1][j - k] + w[i][k])
- 不选第
- 用
num[i]
记录第i
个公司的服务器分配数量
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 100;
int dp[N][N];
int w[N][N];
int num[N];
void solve(){
int n, m;
cin >> n >> m;
for(int i = 1; i <= n; i ++){
for(int j = 1; j <= m; j ++){
cin >> w[i][j];
}
}
for(int i =1; i <= n; i ++){
for(int j = 0; j <= m; j ++){
for(int k = 0; k <= j; k ++){
dp[i][j] = max(dp[i][j],dp[i - 1][j - k] + w[i][k]);
}
}
}
int j = m;
for(int i = n; i ; i --){
for(int k = 1; k <= j; k ++){
if(dp[i][j] == dp[i - 1][j - k] + w[i][k]){
num[i] = k;
j -= k;
break;
}
}
}
cout << dp[n][m] << endl;
for(int i = 1; i <= n; i ++) cout << i << " " << num[i] << endl;
}
int main(){
solve();
return 0;
}