CJOJ P2317 JesseLiu的预算方案

来源:互联网 发布:c语言控制鼠标点击 编辑:程序博客网 时间:2024/05/01 14:16

题目大意:

“我需要你为我制订一个购物的方案。我将要为我的宫殿增置一些家具。有n 种备选家具,家具有主件和附件之分。在购买某个主件的附件之前,我必须先购买其对应的主件。某一主件的附件不会是另一样家具所对应的主件。每一件家具 i 都有自己的价格 x 与重要度 y。要完成这个问题,你需要在 1s 内得出我在花费不超过 m 元的情况下所能得到的家具的价格与重要度乘积的和最大。

方法:

1、读入每个物品,用邻接表存主件和它的附件;

2、扫每一个物品,如果为主件,进入3、;

3、开一个辅助数组,先将主件强制存入数组,再将它的所有附件跑01背包(背包容量要减去主件),跑完之后将 辅助数组 和 主数组 进行比较得到较大值;

4、dp1[m](主数组)即是答案;

注意:

1、开一个辅助数组的原因是:当前主件组可能不选,用辅助数组计算出选当前主件组的最优值,再与主数组相比较得到总的最优值;

2、先for儿子,再for容量,的原因是:当前主件组的附件 有的会选 有的不会选,这样做等于将当前儿子在每一种容量v里面都试一次(可以选多个儿子);

3、对2、的补充:如果是先for容量,再for儿子,就相当于只在当前容量中试一次儿子(只能选一个儿子),这就变成了另一种背包问题——分组背包;


最后再附上一句:任何背包问题其实是对每一件物品在某一个容量中放或不放的选择 ;


#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <algorithm>#include <cmath>#define maxn 30001using namespace std;int m,n;int head[61];int dp1[maxn],dp2[maxn];int w[61],c[61];bool vis[61];struct Edge {int to,dis,next;}edge[61];int edge_num=0;void add(int x, int y) {edge[++edge_num].next=head[x];edge[edge_num].to=y;head[x]=edge_num;}int main() {scanf("%d%d", &m, &n);for(int i=1; i<=n; ++i) {int x,y,z;scanf("%d%d%d", &x, &y, &z);w[i]=x,c[i]=x*y;if(z) {vis[i]=1;add(z,i);}}for(int i=1; i<=n; ++i) {if(!vis[i]) {//找主件 for(int v=w[i]; v<=m; ++v) dp2[v]=dp1[v-w[i]]+c[i];//强制选主件  注意1 for(int j=head[i]; j!=0; j=edge[j].next) {//找儿子 int to=edge[j].to;int k=w[to]+w[i];for(int v=m; v>=k; --v) {//注意2dp2[v]=max(dp2[v],dp2[v-w[to]]+c[to]);}}for(int i=1; i<=m; ++i) dp1[i]=max(dp1[i],dp2[i]);memset(dp2,0,sizeof(dp2));}}printf("%d", dp1[m]);return 0;}//背包问题其实是对每一件物品在某一个容量中放或不放的选择 





0 0
原创粉丝点击