Q1: 金明的预算方案
思路分析:
开心的金明的稍稍变式,本题有个限制就是如果要买归类为附件的物品,必须先买该附件所属的主件,同时每个主件只有 0 个、1 个或 2 个附件。也就是说,对于每一个大类(主件以及其附件),我们有这么几种选择:①不选这个主件。②只选这个主件。③选这个主件,并且选附件1。④选这个主件,并且选附件2。⑤选这个主件,并且选附件1和附件2。同时,我们也只能选择其中的一种。于是这个题便变成了分组背包问题。
参考代码:
#include <bits/stdc++.h>
using namespace std;
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define endl '\n'
#define pb push_back
const int N = 100, M = 32005;
int n, m;
int a[65], b[65];
vector<int> c[65], l[N];
int v[N], w[N], f[M], idx = 1;
inline void slove()
{
cin >> m >> n;
for(int i = 1; i <= n; ++ i)
{
int x, p; cin >> a[i] >> x >> p;
b[i] = a[i] * x;
if(p == 0) c[i].pb(i);
else c[p].pb(i);
}
// 预处理出每一组
for(int i = 1; i <= n; ++ i)
{
int len = c[i].size();
if(len == 0) continue;
else if(len == 1)
{
int x = c[i][0], p = idx;
v[idx] = a[x], w[idx] = b[x], l[p].pb(idx);
++ idx;
}
else if(len == 2)
{
int x = c[i][0], y = c[i][1], p = idx;
v[idx] = a[x], w[idx] = b[x], l[p].pb(idx);
++ idx;
v[idx] = a[x] + a[y], w[idx] = b[x] + b[y], l[p].pb(idx);
++ idx;
}
else
{
int x = c[i][0], y = c[i][1], z = c[i][2], p = idx;
v[idx] = a[x], w[idx] = b[x], l[p].pb(idx);
++ idx;
v[idx] = a[x] + a[y], w[idx] = b[x] + b[y], l[p].pb(idx);
++ idx;
v[idx] = a[x] + a[z], w[idx] = b[x] + b[z], l[p].pb(idx);
++ idx;
v[idx] = a[x] + a[y] + a[z], w[idx] = b[x] + b[y] + b[z], l[p].pb(idx);
++ idx;
}
}
// 完全背包
for(int i = 1; i < idx; ++ i)
{
if(l[i].size() == 0) continue;
for(int j = m; j; -- j)
for(auto k : l[i])
if(j >= v[k])
f[j] = max(f[j], f[j - v[k]] + w[k]);
}
cout << f[m] ;
}
int main()
{
IO;
int _;
_ = 1;
//cin >> _;
while(_ --)
{
slove();
}
return 0;
}
Q2: 最大约数和
思路分析:
01 背包裸题,我们记
S
D
(
x
)
SD(x)
SD(x) 为
x
x
x 的所有约数之和(除
x
x
x 本身),那么这里
x
x
x 和
S
D
(
x
)
SD(x)
SD(x) 分别对应01 背包中的物品体积和价值,题目中的
S
S
S 即是最大体积。
参考代码:
#include <bits/stdc++.h>
using namespace std;
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define endl '\n'
const int N = 1005;
int n;
int w[N], f[N];
inline void slove()
{
cin >> n;
for(int i = 1; i <= n; ++ i)
{
int sum = 0;
for(int x = 1; x <= i / x; ++ x)
{
if(i % x == 0)
{
sum += x;
if(x != i / x)
sum += (i / x);
}
}
sum -= i;
w[i] = sum;
}
for(int i = 1; i <= n; ++ i)
for(int j = n; j >= i; -- j)
f[j] = max(f[j], f[j - i] + w[i]);
cout << f[n] ;
}
int main()
{
IO;
int _;
_ = 1;
//cin >> _;
while(_ --)
{
slove();
}
return 0;
}
End:
今天的题解分享就到这里结束啦,如果有更好的解法或者思路,欢迎大家评论区留言交流!!!