博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
金明的预算方案
阅读量:5160 次
发布时间:2019-06-13

本文共 2659 字,大约阅读时间需要 8 分钟。

原题链接:

带有附件的背包问题,它属于01背包的变式。

这题还好,每一个物品最多只有两个附件,那么我们在对主件进行背包的时候,决策就不再是两个了,而是五个。

还记得01背包的决策是什么吗?

1.不选,然后去考虑下一个

2.选,背包容量减掉那个重量,总值加上那个价值。

 

这个题的决策是五个,分别是:

1.不选,然后去考虑下一个

2.选且只选这个主件

3.选这个主件,并且选附件1

4.选这个主件,并且选附件2

5.选这个主件,并且选附件1和附件2.

这个。。。很好想吧。。。

 

我们知道,01背包的状态转移方程(已进行滚动数组优化)是f[j] = max(f[j],f[j-w[i]]+c[i]),那么,这道题的转移方程也就不难写出了。

等等,你得先判断某个选附件的决策是不是可行的,如果当前的容量还够放第一个,或第二个,或两个都选的附件,那么才能考虑转移。

当然,不选附件的话就不用判啦,直接01背包的转移方程即可。

我们令main_item_w数组表示某个主件的费用,而main_item_c数组表示某个主件的价值。

同样的,用二维数组annex_item_w表示某个附件的费用,annex_item_c表示某个附件的价值,第二维只需要0,1,2这三个数,其中第二维是0的场合表示这个主件i的附件数量,它只能等于0或1或2。第二维是1或者是2的值代表以i为主件的附件1或者附件2的相关信息(费用 价值)。这些数组的信息应该在读入时处理好,具体详见代码。

这样,状态转移方程就是四个。

不选附件的①:f[j] = max(f[j],f[j-main_item_w[i]]+main_item_c[i]);

选附件1的②:f[j] = max(f[j],f[ j - main_item_w[i] - annex_item_w[i][1] ] + main_item_c[i] + annex_item_c[i][1]);

选附件2的③:f[j] = max(f[j],f[ j - main_item_w[i] - annex_item_w[i][2] ] + main_item_c[i] + annex_item_c[i][2]);

选附件1和附件2的④:f[j] = max(f[j],f[ j - main_item_w[i] - annex_item_w[i][1] - annex_item_w[i][2] ] + main_item_c[i] + annex_item_c[i][1] + annex_item_c[i][2]);

已经滚动掉了第一维,道理和正常向的01背包都是一样的,即只有i和i-1有关系,但是这个规律在循环中已经满足了所以完全没必要记录。

目标状态f[n],输出就好。

参考代码:

1 #include 
2 #define maxn 32005 3 using namespace std; 4 int n,m; 5 int v,p,q; 6 int main_item_w[maxn]; 7 int main_item_c[maxn]; 8 int annex_item_w[maxn][3]; 9 int annex_item_c[maxn][3];10 int f[maxn];11 int main(){12 cin >> n >> m;13 for (int i=1;i<=m;i++){14 cin >> v >> p >> q;15 if (!q){16 main_item_w[i] = v;17 main_item_c[i] = v * p;18 }19 else{20 annex_item_w[q][0]++;21 annex_item_w[q][annex_item_w[q][0]] = v;22 annex_item_c[q][annex_item_w[q][0]] = v * p;23 }24 }25 26 for (int i=1;i<=m;i++)27 for (int j=n;main_item_w[i]!=0 && j>=main_item_w[i];j--){28 f[j] = max(f[j],f[j-main_item_w[i]]+main_item_c[i]);29 30 if (j >= main_item_w[i] + annex_item_w[i][1])31 f[j] = max(f[j],f[ j - main_item_w[i] - annex_item_w[i][1] ] + main_item_c[i] + annex_item_c[i][1]);32 33 if (j >= main_item_w[i] + annex_item_w[i][2])34 f[j] = max(f[j],f[ j - main_item_w[i] - annex_item_w[i][2] ] + main_item_c[i] + annex_item_c[i][2]);35 36 if (j >= main_item_w[i] + annex_item_w[i][1] + annex_item_w[i][2])37 f[j] = max(f[j],f[ j - main_item_w[i] - annex_item_w[i][1] - annex_item_w[i][2] ] + main_item_c[i] + annex_item_c[i][1] + annex_item_c[i][2]);38 39 }40 cout << f[n] << endl;41 return 0;42 }

 

转载于:https://www.cnblogs.com/OIerShawnZhou/p/7599615.html

你可能感兴趣的文章
(一一二)图文混排中特殊文字的点击与事件处理
查看>>
iPhone开发经典语录集锦 (转)
查看>>
SVM基础必备常识
查看>>
FPGA时序约束的几种方法 (转)
查看>>
cocos2dx 3.x tolua 分析
查看>>
oracle 外网访问
查看>>
jdbc连接数据库方式问题
查看>>
一步一回头撞在了南墙上
查看>>
POJ2965 The Pilots Brothers' refrigerator
查看>>
C# 2.0 中的新增功能01 分布类与分部方法
查看>>
关于腾讯ip接口一个流传很广的错误用法
查看>>
java 浅拷贝和深拷贝
查看>>
unity如何判断应用的运行平台
查看>>
LAMMPS脚本1
查看>>
Kubernetes 1.10.4 镜像 版本
查看>>
[每天进步一点 -- 流水账]回顾总结
查看>>
[小明学算法]6.字符串匹配算法---KMP
查看>>
url的处理
查看>>
(原创)c#学习笔记10--定义类成员02--类成员的其他议题02--调用重写或隐藏的基类方法...
查看>>
windbg学习----$$(注释说明符)和*(注释行说明符)和.echo
查看>>