题目描述
题目:https://www.luogu.com.cn/problem/P1064
思路分析
一拿到题目看着以为是01背包,但是仔细一看,发现有主件和附件之间的关系,所以不能直接用01背包。后来去查了背包9讲,发现这是个有依赖的背包。大致思路如下:首先,我们需要对每一组主附件进行01背包,找出在一定金钱(背包容量)下的最大价值重要性积的和(好绕口。。。)。
for (register int i = 0; i < gds.size(); i++)
{
for (register int j = 0; j < gds[i].size(); j++)//选附件
{
for (register int k = n; k >= gds[i][j].v; k--)
{
if (j == 0)//选主件的时候,只要放得下都放下去。
{
dp1[i][k] = gds[i][j].v * gds[i][j].p;
dp2[i][k] = j;
}
else//选附件的时候
{
if (dp1[i][k - gds[i][j].v] != 0)
//只有在k - gds[i][j].v容量下,可以选择主件的情况下,才可以选择附件。
{
dp1[i][k] = max(dp1[i][k], dp1[i][k - gds[i][j].v] + gds[i][j].v * gds[i][j].p);//比较,取最大。
}
}
}
}
}
接下来,需要对所有的主附件进行01背包。注意这里的处理,这已经是我能想得到的最好的处理方法了。。。不然需要大改代码。。。
for (register int i = 0; i < gds.size(); i++)
{
for (register int j = n; j >=gds[i][0].v; j--)
{
dp[j] = max(dp[j], dp[j - gds[i][0].v] + dp1[i][gds[i][0].v]);
//比较装下(该主件的最大值)和(不装下该主件下的最大值)的最大值(*)
if (gds[i].size() > 1 && j >= gds[i][0].v + gds[i][1].v)
{
dp[j] = max(dp[j], dp[j - gds[i][1].v - gds[i][0].v] + dp1[i][gds[i][1].v + gds[i][0].v]);
//判断装下主件+附件1的时候的最大值和之前(*)式子的结果,取最大。(**)
}
if (gds[i].size() > 2 && j >= gds[i][0].v + gds[i][2].v)
{
dp[j] = max(dp[j], dp[j - gds[i][0].v - gds[i][2].v] + dp1[i][gds[i][0].v + gds[i][2].v]);//取装下主件+附件2和之前的所有结果的最大值
}
if (gds[i].size() > 2 && j >= gds[i][0].v + gds[i][1].v + gds[i][2].v)
{
dp[j] = max(dp[j], dp[j - gds[i][0].v - gds[i][1].v - gds[i][2].v] + dp1[i][gds[i][1].v + gds[i][2].v + gds[i][0].v]);
//取装下主件+附件1+附件2与之前所有结果的最大值
}
}
}
剩下的,和普通背包一样,输出n容量下的最大值即可(好难。。。)
完整代码
#include <iostream>
#include <vector>
#include <algorithm>
#include <map>
#include <cstring>
#include <cstdlib>
using namespace std;
struct good {
int v;
int p;
};
map<int, int> re;
vector<vector<good>> gds;
long dp1[70][30005] = { 0 };
long dp2[70][30005] = { 0 };
long dp[32005] = { 0 };
int main()
{
int n, m;
cin >> n >> m;
int dis = 0;
int key = 0;
for (int i = 0; i < m; i++)
{
vector<good> tmp;
good t;
cin >> t.v >> t.p;
int j;
cin >> j;
if (j == 0)
{
re[i + 1] = key++;
tmp.push_back(t);
gds.push_back(tmp);
}
else
{
gds[re[j]].push_back(t);
dis++;
}
}
memset(dp1, 0, sizeof(dp1));
for (register int i = 0; i < gds.size(); i++)
{
for (register int j = 0; j < gds[i].size(); j++)//选附件
{
for (register int k = n; k >= gds[i][j].v; k--)
{
if (j == 0)
{
dp1[i][k] = gds[i][j].v * gds[i][j].p;
dp2[i][k] = j;
}
else
{
if (dp1[i][k - gds[i][j].v] != 0)
{
dp1[i][k] = max(dp1[i][k], dp1[i][k - gds[i][j].v] + gds[i][j].v * gds[i][j].p);
}
}
}
}
}
for (register int i = 0; i < gds.size(); i++)
{
for (register int j = n; j >=gds[i][0].v; j--)
{
dp[j] = max(dp[j], dp[j - gds[i][0].v] + dp1[i][gds[i][0].v]);
if (gds[i].size() > 1 && j >= gds[i][0].v + gds[i][1].v)
{
dp[j] = max(dp[j], dp[j - gds[i][1].v - gds[i][0].v] + dp1[i][gds[i][1].v + gds[i][0].v]);
}
if (gds[i].size() > 2 && j >= gds[i][0].v + gds[i][2].v)
{
dp[j] = max(dp[j], dp[j - gds[i][0].v - gds[i][2].v] + dp1[i][gds[i][0].v + gds[i][2].v]);
}
if (gds[i].size() > 2 && j >= gds[i][0].v + gds[i][1].v + gds[i][2].v)
{
dp[j] = max(dp[j], dp[j - gds[i][0].v - gds[i][1].v - gds[i][2].v] + dp1[i][gds[i][1].v + gds[i][2].v + gds[i][0].v]);
}
//cout << dp[j] << " ";
}
//cout << endl;
}
cout << dp[n];
return 0;
}