洛谷 P1064: [NOIP 2006 提高组] 金明的预算方案
解题过程
首先发现这是一个典型的依赖 DP,但是进一步观察可发现最多只有一层。
20pts
于是我们发现每次无非就是只买主件、买主件和第一个附件、买主件和第二个附件以及买主件和所有附件这四种可能。于是我们在每次输入时判断这个部件是不是主件,如果是就直接加入到后续的物品中,如果不是则再判断是不是第一个附件,如果是则把“买主件和第一个附件”这种情况加入到后续的物品中,如果还不是则把“买主件和第二个附件”以及“买主件和所有附件”这两种情况加入到后续的物品中。
接下去再用 01 背包即可。
点击查看代码
#include <bits/stdc++.h>
#define int long long
const int N = 2e5 + 5;
const int Mod = 1e9 + 7;
using namespace std;
int n, m;
int v[N], w[N], q[N], first[N];
int vi[N], wi[N];
int cnt;
int f[N];
signed main()
{
cin >> n >> m;
for (int i = 1; i <= m; i++)
{
cin >> v[i] >> w[i] >> q[i];
if (!q[i])
{
wi[++cnt] = v[i];
vi[cnt] = v[i] * w[i];
}
else if (!first[q[i]])
{
first[q[i]] = i;
wi[++cnt] = v[q[i]] + v[i];
vi[cnt] = v[q[i]] * w[q[i]] + v[i] * w[i];
}
else
{
wi[++cnt] = v[q[i]] + v[i];
vi[cnt] = v[q[i]] * w[q[i]] + v[i] * w[i];
wi[++cnt] = v[q[i]] + v[first[q[i]]] + v[i];
vi[cnt] = v[q[i]] * w[q[i]] + v[first[q[i]]] * w[first[q[i]]] + v[i] * w[i];
}
}
for (int i = 1; i <= cnt; i++)
{
for (int j = n; j >= wi[i]; j--)
{
f[j] = max(f[j], f[j - wi[i]] + vi[i]);
}
}
cout << f[n];
return 0;
}
40pts
当然,这样会 WA。仔细观察,发现问题出在如果选了这四种情况中的一个,别的情况就不能选了。于是我们再改用分组背包,采用 vector 记录每个主件的所有情况。
点击查看代码
#include <bits/stdc++.h>
#define int long long
const int N = 3.2e4 + 5;
const int M = 65;
const int Mod = 1e9 + 7;
using namespace std;
int n, m;
vector<int> vi[M], wi[M];
int f[N];
signed main()
{
cin >> n >> m;
for (int i = 1; i <= m; i++)
{
int v, w, q;
cin >> v >> w >> q;
if (!vi[q].size())
{
wi[i].push_back(v);
vi[i].push_back(v * w);
}
else if (vi[q].size() == 1)
{
wi[q].push_back(wi[q][0] + v);
vi[q].push_back(vi[q][0] + v * w);
}
else
{
wi[q].push_back(wi[q][0] + v);
vi[q].push_back(vi[q][0] + v * w);
wi[q].push_back(wi[q][0] + wi[q][1] + v);
vi[q].push_back(vi[q][0] + vi[q][1] + v * w);
}
}
for (int i = 1; i <= m; i++)
{
for (int j = n; j >= 0; j--)
{
for (int k = 0; k < vi[i].size(); k++)
{
if (j >= wi[i][k])
{
f[j] = max(f[j], f[j - wi[i][k]] + vi[i][k]);
}
}
}
}
cout << f[n];
return 0;
}
100pts
观察上一次的代码,发现在处理“买主件和所有附件”这种情况时会出现问题,因为在 wi[q][1] 中已经包含了 wi[q][0],vi 也一样。
删除 wi[q][0] 与 vi[q][0] 即可。

浙公网安备 33010602011771号