题目描述

金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间。更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过NNN元钱就行”。今天一早,金明就开始做预算了,他把想买的物品分为两类:主件与附件,附件是从属于某个主件的,下表就是一些主件与附件的例子:

主件 附件

电脑 打印机,扫描仪

书柜 图书

书桌 台灯,文具

工作椅 无

如果要买归类为附件的物品,必须先买该附件所属的主件。每个主件可以有000个、111个或222个附件。附件不再有从属于自己的附件。金明想买的东西很多,肯定会超过妈妈限定的NNN元。于是,他把每件物品规定了一个重要度,分为555等:用整数1−51-51−5表示,第555等最重要。他还从因特网上查到了每件物品的价格(都是101010元的整数倍)。他希望在不超过NNN元(可以等于NNN元)的前提下,使每件物品的价格与重要度的乘积的总和最大。

设第jjj件物品的价格为v[j]v_[j]v[​j],重要度为w[j]w_[j]w[​j],共选中了kkk件物品,编号依次为j1,j2,…,jkj_1,j_2,…,j_kj1​,j2​,…,jk​,则所求的总和为:

v[j1]×w[j1]+v[j2]×w[j2]+…+v[jk]×w[jk]v_[j_1] \times w_[j_1]+v_[j_2] \times w_[j_2]+ …+v_[j_k] \times w_[j_k]v[​j1​]×w[​j1​]+v[​j2​]×w[​j2​]+…+v[​jk​]×w[​jk​]。

请你帮助金明设计一个满足要求的购物单。

输入格式

第111行,为两个正整数,用一个空格隔开:

NmN mNm (其中N(<32000)N(<32000)N(<32000)表示总钱数,m(<60)m(<60)m(<60)为希望购买物品的个数。) 从第222行到第m+1m+1m+1行,第jjj行给出了编号为j−1j-1j−1的物品的基本数据,每行有333个非负整数

vpqv p qvpq (其中vvv表示该物品的价格(v<10000v<10000v<10000),p表示该物品的重要度(1−51-51−5),qqq表示该物品是主件还是附件。如果q=0q=0q=0,表示该物品为主件,如果q>0q>0q>0,表示该物品为附件,qqq是所属主件的编号)

输出格式

一个正整数,为不超过总钱数的物品的价格与重要度乘积的总和的最大值(<200000<200000<200000)。

输入输出样例

输入 #1

1000 5
800 2 0
400 5 1
300 5 1
400 3 0
500 2 0
输出 #1

2200
魔改01背包,思路是把选附件的情况和选主件合并到一起考虑而非单独考虑,一共只有五种情况。
#include <bits/stdc++.h>
using namespace std;
int n,m;
int dp[]={};
int cost[][]={};//价值,0为主,1,2为附件
int val[][]={};//重要度
int tot[][]={};//重要度*价值
int main()
{
cin>>n>>m;
int i;
for(i=;i<=m;i++)
{
int v,p,q;
cin>>v>>p>>q;
if(!q)
{
cost[i][]=v;
val[i][]=p;
tot[i][]=p*v;
}
else if(!cost[q][])//第一个附件
{
cost[q][]=v;
val[q][]=p;
tot[q][]=p*v;
}
else
{
cost[q][]=v;
val[q][]=p;
tot[q][]=p*v;
}
}
for(i=;i<=m;i++)
{
if(!cost[i][])continue;//非主件跳过(虽然说不加也没有任何影响,因为一个max保证了当i为附件时的0一定不会被考虑进去
int j;
for(j=n;j>=;j--)
{
if(j>=cost[i][])dp[j]=max(dp[j],dp[j-cost[i][]]+tot[i][]);//不选和只选主件
if(j>=cost[i][]+cost[i][])dp[j]=max(dp[j],dp[j-cost[i][]-cost[i][]]+tot[i][]+tot[i][]);//选主件和第一件
if(j>=cost[i][]+cost[i][])dp[j]=max(dp[j],dp[j-cost[i][]-cost[i][]]+tot[i][]+tot[i][]);//主件和第二件
if(j>=cost[i][]+cost[i][]+cost[i][])dp[j]=max(dp[j],dp[j-cost[i][]-cost[i][]-cost[i][]]+tot[i][]+tot[i][]+tot[i][]);//主件和第一,二件
} }
cout<<dp[n];
return ;
}

下面是一开始写的假代码,不知道为啥还能混到80分。可能的问题是输入时有可能先输入附件,按我那么做的话附件在前面,不是由选其对应主件递推而来,这个附件肯定就不会选上,所以要排序,1~m应该是先主件后附件,q的值也要改,但不知道哪里有问题...求各位大佬指教。

#include <bits/stdc++.h>//80分假代码,问题在32行
using namespace std;
int n,m;
struct good//商品结构体
{
int v;
int p;
int q;
int num;
}g[];
bool cmp(good a,good b)
{
return a.q<b.q;
}
struct state//以状态作为dp数组的元素
{
bool vis[];
int val;
};
state dp[][];
int main()
{
cin>>n>>m;
int i,j,k;
for(i=;i<=m;i++)
{
int v,p,q;
scanf("%d%d%d",&v,&p,&q);
g[i].v=v;
g[i].p=p;
g[i].q=q;
g[i].num=i;//方便排序后查找
} // sort(g+1,g+m+1,cmp);//不能sort? 因为排序后原来的下标也变了 good结构体里的q变量也不能用了 但如果不sort的话假设第一个物体就是附件 那么i从1开始肯定拿不到这个物品了 不满足无后效性 所以说必须排序,然排序后如何调整q的值也是问题
// for(i=1;i<=m;i++)
// {
// for(j=1;j<=m;j++)
// {
// if(g[i].q==g[j].num&&g[i].q!=0&&g[j].q==0)
// {
// // g[i].q=j;
// g[j].q=i;
// }
// }
// } for(i=;i<=m;i++)
{
for(j=;j<=n;j++)
{
dp[i][j].val=;
for(k=;k<=m;k++)dp[i][j].vis[k]=;
}
}
for(i=;i<=m;i++)
{
for(j=;j<g[i].v;j++)//不能漏
{
dp[i][j]=dp[i-][j];
}
for(j=g[i].v;j<=n;j++)
{
if(g[i].q)//自己是附件
{
if(dp[i-][j].val>dp[i-][j-g[i].v].val+g[i].v*g[i].p)
{
dp[i][j].val=dp[i-][j].val;
memcpy(dp[i][j].vis,dp[i-][j].vis,sizeof(bool)*);
}
else if(dp[i-][j].val<=dp[i-][j-g[i].v].val+g[i].v*g[i].p&&dp[i-][j-g[i].v].vis[g[i].q])//附件的主件已经选择
{
dp[i][j].val=dp[i-][j-g[i].v].val+g[i].v*g[i].p;
memcpy(dp[i][j].vis,dp[i-][j-g[i].v].vis,sizeof(bool)*);//一定要整个复制过来
dp[i][j].vis[i]=;
}
else
{
dp[i][j].val=dp[i-][j].val;
memcpy(dp[i][j].vis,dp[i-][j].vis,sizeof(bool)*);
}
}
else//自己是主件
{
if(dp[i-][j].val>dp[i-][j-g[i].v].val+g[i].v*g[i].p)//不能取等?因为如果相等的话其实应该买这件物品,为以后增加可能
{
dp[i][j].val=dp[i-][j].val;
memcpy(dp[i][j].vis,dp[i-][j].vis,sizeof(bool)*);
}
else
{
dp[i][j].val=dp[i-][j-g[i].v].val+g[i].v*g[i].p;
memcpy(dp[i][j].vis,dp[i-][j-g[i].v].vis,sizeof(bool)*);//一定要整个复制过来
dp[i][j].vis[i]=;
}
}
}
}
int ans=;
state mmax;
for(i=;i<=m;i++)
{
for(j=;j<=n;j++)
{
// ans=max(ans,dp[i][j].val);
if(ans<dp[i][j].val)
{
ans=dp[i][j].val;
mmax=dp[i][j];
}
}
}
cout<<ans;
}

洛谷P1064 金明的预算方案(01背包)的更多相关文章

  1. 洛谷 P1064 金明的预算方案(01背包问题)

    传送门:Problem 1064 https://www.cnblogs.com/violet-acmer/p/9852294.html 题解: 这道题是 “01”背包问题的变形. 如果不考虑买附件必 ...

  2. 洛谷P1064 金明的预算方案

    题目描述 金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间.更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过NN元钱就行”. ...

  3. 洛谷 P1064 金明的预算方案【有依赖的分组背包】

    题目描述 金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间.更让他高兴的是,妈妈昨天对他说:"你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N元钱 ...

  4. 洛谷 P1064 金明的预算方案

    题目描述 金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间.更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N元钱就行”.今 ...

  5. 洛谷 P1064 金明的预算方案 (有依赖的0/1背包)

    题目描述 金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间.更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过NN元钱就行”. ...

  6. [NOIP2006] 提高组 洛谷P1064 金明的预算方案

    题目描述 金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间.更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N元钱就行”.今 ...

  7. 洛谷 P1064 金明的预算方案(有依赖的背包问题)

    题目描述 金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间.更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N元钱就行”.今 ...

  8. Java实现 洛谷 P1064 金明的预算方案

    题目描述 金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间.更让他高兴的是,妈妈昨天对他说:"你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过NN元 ...

  9. 洛谷 P1064 金明的预算方案【DP/01背包-方案数】

    题目背景 uim神犇拿到了uoi的ra(镭牌)后,立刻拉着基友小A到了一家--餐馆,很低端的那种. uim指着墙上的价目表(太低级了没有菜单),说:"随便点". 题目描述 不过ui ...

随机推荐

  1. 【C语言】思维导图

    长按图片或右键另存为保存哦(´-ω-`)

  2. C++-有感

    今日在图书馆待了差不多一天,我都忘了我吃饭了没,拿着看视频学习,没啦,主要还是看书,突然感觉有点写不动了. 明天开始不带电脑了,准备把数据结构书重新过一遍,算了,还是不用C++写了,感觉C++居然做题 ...

  3. 一看就会一做就废系列:说说 RECOVER DATABASE(上)

    这里是:一看就会,一做就废系列 数据库演示版本为 19.3 (12.2.0.3) 该系列涉及恢复过程中使用的 个语句: 1. recover database 2. recover database ...

  4. js面向对象的程序设计 --- 下篇 继承启蒙

    继承是oo语言中一个最为人津津乐道的概念.ECMAScript支持实现继承,而且实现继承只要是靠原型链来实现的 ·原型链 其基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法. 简单回顾一 ...

  5. Vue中父组件向子组件echarts传值问题

    原文链接:https://blog.csdn.net/Uookic/article/details/80638883?utm_source=copy 问题:当父组件传值给子组件echarts时,发现子 ...

  6. JS 获取随机颜色值

    获取随机颜色值 function fn1(){ return '#' + Math.floor( Math.random() * 0xffffff ).toString(16); } function ...

  7. Educational Codeforces Round 76 (Rated for Div. 2) C. Dominated Subarray

    Let's call an array tt dominated by value vv in the next situation. At first, array tt should have a ...

  8. 题解【洛谷P2323】 [HNOI2006]公路修建问题

    题面 题解 跑两遍\(Kruskal\),第一次找出\(k\)条一级公路,第二次找出\(n - k - 1\)条二级公路,直接计算\(MST\)的权值之和即可. 代码 #include <ios ...

  9. 传奇服务端添加双倍经验卷的方法 双倍经验卷轴DB示例展示

    第一步我们在DBC数据库中添加好双倍经验卷轴DB,以下是现成的双倍经验卷DB,导入到DB里面就可以了. 222;双倍经验卷;31;0;1;20;0;0;265;0;0;0;0;0;0;0;0;0;0; ...

  10. Unity手机端手势基本操作

    主要有单指移动3D物体.单指旋转3D物体.双指缩放3D物体. 基类 using UnityEngine; using System.Collections; /// <summary> / ...