动态规划
专题。洛谷 P1064 金明的预算方案
题目描述
输入输出格式
说明
NOIP 2006 提高组 第二题
时空限制
- 时间:1000ms
- 空间:128MB
思路
这是 带附件的背包问题
,我也是第一次接触,看了很久别人的题解,终于找到一个看懂了的题解。首先用一个结构体 good 记录物品的属性, good[i].v 表示物品 i 价格,good[i].w 表示物品 i 重要度。
然后,因为题目意思是至多带两个附件,于是在进行递推公式前,需要进行整理。用一个 flag 数组表示当前物品是否访问过。
1. z=0:表示该物品是主件,价格和总价值存入 good[i][0] 结构体
2. z!=0:
flag[z]=0:表示当前物品没有访问过,存入 good[z][1] 结构体,表示附件一,同时将 flag[z] 置为 1
flag[z]!=0:表示当前物品已经访问过,存入 good[z][2] 结构体,表示附件二
下面就可以写出递推公式了。
1. j >= good[i][0].v 即只选主件:
dp[j] = max(dp[j], dp[j-good[i][0].v]+good[i][0].w); //不选当前件,选择当前件所以要花费当前物品的费用,再加上总价值
2. j >= good[i][0].v+good[i][1].v 即选主件+附件1:
dp[j] = max(dp[j], dp[j-good[i][0].v-good[i][1].v] + good[i][0].w+good[i][1].w);
3. j >= good[i][0].v+good[i][2].v) 即选主件+附件2:
dp[j] = max(dp[j], dp[j-good[i][0].v-good[i][2].v] + good[i][0].w+good[i][2].w);
4. j >= good[i][0].v+good[i][1].v+good[i][2].v) 即都选:
dp[j] = max(dp[j], dp[j-good[i][0].v-good[i][1].v-good[i][2].v] + good[i][0].w+good[i][1].w+good[i][2].w);
代码
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <math.h>
using namespace std;
int n,m;
struct goods{
int v,w;
}good[100][3]; //0为主件、1为附件1、2为附件2
int flag[100],dp[1000000];
int main(){
memset(flag,0,sizeof(flag));
scanf("%d%d",&n, &m);
for(int i = 1; i <= m; ++i){ //从1开始
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
if(z == 0){ //表示是主件
good[i][0].v = x;
good[i][0].w = x*y;
}
else{ //是附件
if(flag[z] == 0){
good[z][1].v = x; //注意:第一维下标是z,这个错找了半个小时。
good[z][1].w = x*y;
flag[z] = 1; //表示是否访问过
}
else{
good[z][2].v = x;
good[z][2].w = x*y;
//flag[z] = 1;
}
}
}
for(int i = 1; i <= m; ++i){ //i <= 可选的物品种类,从1开始
for(int j = n; j >= 0; --j){ //j = 总钱数
if(j >= good[i][0].v){ //只选主件
dp[j] = max(dp[j], dp[j-good[i][0].v]+good[i][0].w); //不选当前件,选择当前件所以要花费当前物品的费用,再加上总价值
}
if(j >= good[i][0].v+good[i][1].v){ //选主件+附件1
dp[j] = max(dp[j], dp[j-good[i][0].v-good[i][1].v] +
good[i][0].w+good[i][1].w);
}
if(j >= good[i][0].v+good[i][2].v){ //选主件+附件2
dp[j] = max(dp[j], dp[j-good[i][0].v-good[i][2].v] +
good[i][0].w+good[i][2].w);
}
if(j >= good[i][0].v+good[i][1].v+good[i][2].v){ //都选
dp[j] = max(dp[j], dp[j-good[i][0].v-good[i][1].v-good[i][2].v]
+ good[i][0].w+good[i][1].w+good[i][2].w);
}
}
}
printf("%d", dp[n]);
return 0;
}