注意:此篇题解作者文字表述力极差,思路极为混乱。请谨慎阅读,有不严谨或不准确的地方可以提出建议,谢谢。
注意:此题解同样适用于附件个数最多为59个的升级版中。
注意:此题解文字描述内部分变量类型是错误的(这里指long long开成了int),一切变量类型以完整代码为准。
注意:此题解完整代码与文字内容仅仅是思路相同,变量名存在不统一现象。
文字描述 | 完整代码 |
a | B |
b | A |
dp | DP |
基础分析
价值=价格*重要程度
最终要求的是我们买的物品所有价值之和且最大
思路
首先,我们的附件必须要依托于主件
我们可以先跳过附件
只对主件进行处理
我们需要知道这个主件的有哪些附件,这些附件的重要程度和价格
这时我们可以用一个结构体存放物品信息。
结构体 struct
struct node{
int v;//价格
int w;//价值(重要程度*价格)
};
node a[100][100000];
a[i][j]的含义是:
(假设第i件物品一定为主件)
a[i][j]就是第i件物品的第j件附件
int num[100]//用于存放每个下标为i的主件的附件个数
node b[100];//下标为i的主件的信息
输入时输入n,m
n指的是我们拥有的钱数
m指的是想要的物品个数
然后我们通过判断输入的第三个数也就是题目中的q,即类型,选择是将其存入b数组,还是存入a数组并num中对应的值++。
然后我们进行dp操作
int dp[100][40000];//dp在这里的含义是dp[i][j]是指前i个物品中总价格为j
的几件或一件物品的价值。
dp操作
首先判断是否为主件,如果不是,将上一层的dp数组顺承到下一行
可能不太严谨,能理解就行
即
for(int j=1;j<=n;j++)
{
dp[i][j]=dp[i-1][j];
}
如果是的话,我们首先把
dp[i][b[i].v]=b[i].w;
因为我们这时一定会选这个主件,所以我们需要将其转移过来。
接下来我们来dp这个主件的附件
由于我们用的是01背包,而且为了节约空间,我们删去了一维数组,所以我们需要倒序循环。当我们选择一个附件,且此附件相对应的位置已经被存过,就可以进行转移
dp[i][j]=max(dp[i][j],dp[i][j-a[i][k].v]+a[i][k].w);
即
for(int k=1;k<=num[i];k++)
{
for(int j=m;j>=a[i][k].v;j--)
{
if(dp[i][j-a[i][k].v]!=0)
{
dp[i][j]=max(dp[i][j],dp[i][j-a[i][k].v]+a[i][k].w);
}
}
}
因为我们在转移过程中有些附件它不能买,或一些位置没有填上,所以我们需要取这一排和前一排的最大值,来补上一些没有值的位置。
即
for(int j=1;j<=n;j++)
{
dp[i][j]=max(dp[i][j],dp[i-1][j]);
}
最后我们输出dp[n][m]就行了。
完整代码
#include<bits/stdc++.h>
using namespace std;
#define N 65
#define M 42005
struct node
{
long long v,w;
}A[N];
struct node B[N][N];
int n,m,num[N];
long long DP[N][M];
int main()
{
scanf("%d%d",&m,&n);
for(int i=1;i<=n;i++)
{
int aa,bb,cc;
scanf("%d%d%d",&aa,&bb,&cc);//价格 重要度 类型
bb*=aa;//求出真·价值
//这时a是价格
//b是价值
if(cc==0)
{
A[i].v=aa;
A[i].w=bb;
}
else
{
B[cc][++num[cc]].v=aa;
B[cc][num[cc]].w=bb;
}
}
for(int i=1;i<=n;i++)
{
if(A[i].v==-1)
{
for(int j=0;j<=m;j++)
{
DP[i][j]=DP[i-1][j];
}
}
else
{
DP[i][A[i].v]=A[i].w;
for(int j=A[i].v;j<=m;j++)//A[i].v+1???
{
DP[i][j]=max(DP[i][j],DP[i-1][j-A[i].v]+A[i].w);
}
for(int k=1;k<=num[i];k++)
{
for(int j=m;j>=B[i][k].v;j--)
{
if(DP[i][j-B[i][k].v]!=0)
{
DP[i][j]=max(DP[i][j],DP[i][j-B[i][k].v]+B[i][k].w);
}
}
}
for(int j=0;j<=m;j++)
{
DP[i][j]=max(DP[i][j],DP[i-1][j]);
}
}
}
printf("%lld",DP[n][m]);
return 0;
}