洛谷P1064 金明的预算方案(01背包)
题目描述
金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间。更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过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)。
输入输出样例
1000 5
800 2 0
400 5 1
300 5 1
400 3 0
500 2 0
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背包)的更多相关文章
- 洛谷 P1064 金明的预算方案(01背包问题)
传送门:Problem 1064 https://www.cnblogs.com/violet-acmer/p/9852294.html 题解: 这道题是 “01”背包问题的变形. 如果不考虑买附件必 ...
- 洛谷P1064 金明的预算方案
题目描述 金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间.更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过NN元钱就行”. ...
- 洛谷 P1064 金明的预算方案【有依赖的分组背包】
题目描述 金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间.更让他高兴的是,妈妈昨天对他说:"你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N元钱 ...
- 洛谷 P1064 金明的预算方案
题目描述 金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间.更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N元钱就行”.今 ...
- 洛谷 P1064 金明的预算方案 (有依赖的0/1背包)
题目描述 金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间.更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过NN元钱就行”. ...
- [NOIP2006] 提高组 洛谷P1064 金明的预算方案
题目描述 金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间.更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N元钱就行”.今 ...
- 洛谷 P1064 金明的预算方案(有依赖的背包问题)
题目描述 金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间.更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N元钱就行”.今 ...
- Java实现 洛谷 P1064 金明的预算方案
题目描述 金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间.更让他高兴的是,妈妈昨天对他说:"你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过NN元 ...
- 洛谷 P1064 金明的预算方案【DP/01背包-方案数】
题目背景 uim神犇拿到了uoi的ra(镭牌)后,立刻拉着基友小A到了一家--餐馆,很低端的那种. uim指着墙上的价目表(太低级了没有菜单),说:"随便点". 题目描述 不过ui ...
随机推荐
- 剑指offer 面试题 删除链表中重复的节点
题目描述 在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针. 例如,链表1->2->3->3->4->4->5 处理后 ...
- 微信环境中如何实现跳转到手机默认外部浏览器下载apk文件
由于微信的限制,应用文件在内置浏览器中下载全部被屏蔽掉,造成很多人用微信扫描二维码下载时点击下载按钮没反应,我想到的是做一个提示用户在浏览器中打开下载.其实原来很简单,就是判断当前是在微信内置浏览器中 ...
- 数位DP 不要62
数位DP的问法是从某个数到某个数的区间里,求出满足题目要求的个数: 如本题所说的不要62和4,就是求出这个区间内,满足这一条件的数: 比如问 6 199的这个区间内满足条件的数,那么就求出1到199满 ...
- bzoj4199: [Noi2015]品酒大会 (并查集 && 后缀数组)
据说用后缀自动机 + dp也能做 然而并不会 后缀数组的做法呢 就是先建个后缀数组,求出height值,此时如果直接找,复杂度是n ^ 2的,肯定会超时. 但是height大的值是不会对小的产生影响的 ...
- 解决:配置虚拟主机,重启apache,[warn] _default_ VirtualHost overlap on port 80, the first has precedence
http://blog.csdn.net/kaizhu_qin/article/details/17506293 很多第一次配置apache的虚拟主机的时候,以为配置第一个虚拟主机完成以后,以后就不会 ...
- Object的rest和spread方法
//将多个对象合并到一个对象里 const input = { a: 1, b: 2 } const test = { d: 5 } const output = { ...input, ...tes ...
- monkey工具使用(未完待续)
monkey命令详解: 转自:http://blog.csdn.net/jlminghui/article/details/38238443 http://www.cnblogs.com/wfh198 ...
- c#修改项目名称
1.修改解决方案名称 右键,重命名 2.修改项目名称 右键,重命名 3.修改程序集名称和默认命名空间 项目,属性 4.替换解决方案中的名称 编辑,替换,替换范围默认整个解决方案 5.用记事本打开.sl ...
- FreeRTOS学习笔记1:任务
任务特性每个任务有自己的环境,不依赖于其他任务与调度器任何时间点只有一个任务运行.由调度器决定上下文环境:(寄存器值.堆栈内容等)调度器保证的就是任务开始执行时的上下文环境与上一次退出时相同所以每个任 ...
- Mac系统升级后git没法使用的问题
今天更新了mac系统(Catalina)发现之前的项目没法提交,然后大概查了一下啊mac更新方面的问题 mac每次更新时系统就会卸载xcode 在终端输入 xcode-select --instal ...