https://vjudge.net/problem/HRBUST-1377
本题由三种思路,但是第三种和第一种感觉差不多。
1 可以发现一个物品最多五种状态。于是用5种状态进行01背包。
要注意 状态转移的过程。
2 树形dp,其实也是01背包的层次过程。。
3 分组背包。但是同普通的分组背包不一样的是,选附件也要选主件。所以我在 分组数据里放一个(0,0)。dp的时候加上主件。
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int maxn=70;
int a[maxn];
int b[maxn];
int belong[maxn];
int dp[maxn][32100];
int m,n;
int treedp(int cost,int num){
if(cost>0){
for(int i=1;i<=n;i++){
if(belong[i]==num)//如果属于是当前节点的自孩子背包
{ for(int j=0;j<=cost-a[i];j++)
dp[i][j]=dp[num][j]+a[i]*b[i];//装进去这个点。
treedp(cost-a[i],i);
for(int x=0;x<=cost;x++)
if(x>=a[i])
dp[num][x]=max(dp[num][x],dp[i][x-a[i]]);
else
dp[num][x]=dp[num][x];
}
}
}
return 0;
}
int main()
{
while(~scanf("%d%d",&m,&n)){
//m/=100;
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++){
scanf("%d%d%d",&a[i],&b[i],&belong[i]);
}
treedp(m,0);
for(int i=0;i<=n;i++){
for(int j=0;j<=m;j++)
printf("%d ",dp[i][j]);
cout<<endl;
}
printf("%d\n",dp[0][m]);
}
return 0;
}
转化成01背包
#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
/*第一种方法:直接分5种情况。
每种进行01 背包(意思就是啊,
这5种情况只会发生一种情况)
第二种:
*/
const int maxn = 40000;
int dp[70][maxn];
int value[70][3],imp[70][3];
int main()
{
int n,m;
int v,p,q;
while(~scanf("%d%d",&m,&n)){
memset(value,0,sizeof(value));
memset(imp,0,sizeof(imp));
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++){
scanf("%d%d%d",&v,&p,&q);
if(!q){
value[i][0]=v;
imp[i][0]=p;
}
else{
if(!value[q][1]){
value[q][1]=v;
imp[q][1]=p;
}
else{
value[q][2]=v;
imp[q][2]=p;
}
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(j>=value[i][0]){
dp[i][j]=max(dp[i-1][j],dp[i-1][j-value[i][0]]+value[i][0]*imp[i][0]);
if(j>=(value[i][0]+value[i][1]))
dp[i][j]=max(dp[i][j],dp[i-1][j-value[i][0]-value[i][1]]+value[i][0]*imp[i][0]+value[i][1]*imp[i][1]);
if(j>=(value[i][0]+value[i][2]))
dp[i][j]=max(dp[i][j],dp[i-1][j-value[i][0]-value[i][2]]+value[i][0]*imp[i][0]+value[i][2]*imp[i][2]);
if(j>=(value[i][0]+value[i][2]+value[i][1]))
dp[i][j]=max(dp[i][j],dp[i-1][j-value[i][0]-value[i][2]-value[i][1]]+value[i][0]*imp[i][0]+value[i][2]*imp[i][2]+value[i][1]*imp[i][1]);
}
else
dp[i][j]=dp[i-1][j];
}
}
printf("%d\n",dp[n][m]);
}
return 0;
}
#include <iostream>
#include <cstring>
#include <bits/stdc++.h>
using namespace std;
const int maxn=70;
vector<pair<int,int> >v[maxn];
int va[maxn];
int imp[maxn];
int dp[50006];
// 分组背包,比01背包泛化能力要强。
int main()
{ int m,allv,temp;
scanf("%d%d",&allv,&m);
for(int i=1;i<=m;i++){
scanf("%d%d%d",&va[i],&imp[i],&temp);
if(!temp){
v[i].push_back(make_pair(0,0));
;
}
else{
int siz=v[temp].size();
for(int j=0;j<siz;j++)
v[temp].push_back(make_pair(va[i]+v[temp][j].first,imp[i]*va[i]+v[temp][j].second));
//v[temp].push_back(make_pair(va[i],va[i]*imp[i]));
}
}
memset(dp,0,sizeof(dp));
for(int i=1;i<=m;i++){
if(!v[i].size())continue;
//for(int j=0;j<v[i].size();j++){
//cout<<v[i][j].first<<"wupin"<<v[i][j].second<<endl;
for(int val=allv;val>=0;val--){
for(int j=0;j<v[i].size();j++)
if(val>=v[i][j].first+va[i])
dp[val]=max(dp[val-v[i][j].first-va[i]]+v[i][j].second+va[i]*imp[i],dp[val]);
}
//}
}
printf("%d\n",dp[allv]);
return 0;
}