题目:https://www.luogu.org/problem/P1060
题目:noip2006普及组T2
金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间他自己专用的很宽敞的房间。更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N元钱就行”。今天一早金明就开始做预算,但是他想买的东西太多了,肯定会超过妈妈限定的N元。于是,他把每件物品规定了一个重要度,分为5等:用整数1−5表示,第5等最重要。他还从因特网上查到了每件物品的价格(都是整数元)。他希望在不超过N元(可以等于N元)的前提下,使每件物品的价格与重要度的乘积的总和最大。
设第j件物品的价格为v[j],重要度为w[j],共选中了k件物品,编号依次为j1,j2,…,jk则所求的总和为:
v[j1]×w[j1]+v[j2]×w[j2]+…+v[jk]×w[jk]。
请你帮助金明设计一个满足要求的购物单。
第一行,为2个正整数,用一个空格隔开:Nm(其中N(<30000)表示总钱数,m(<25)为希望购买物品的个数。)
从第2行到第m+1行,第jjj行给出了编号为j−1的物品的基本数据,每行有2个非负整数v,p(其中v表示该物品的价格(v≤10000),p表示该物品的重要度(1−5)
1个正整数,为不超过总钱数的物品的价格与重要度乘积的总和的最大值(<100000000)。
这是一道十分简单的DP题目,但是由于我本人的过于菜不屑于做题,所以导致把物品的价值范围和总价的范围搞反了……真是多么愚蠢让人发现自己漏洞的错误啊!
回归正题
先说一个无所谓的小细节,由于取得是物品的价格和重要度的乘积,全题与重要度无瓜,所以一开始就可以直接保存乘积,当然其实保存价格也是差不多的。
主要思路的话呢,这道题呢,其实显而易见是很模板的01背包。要不就买,要不就不买,两种情况。所以
f[i][j]=max(f[i-1][j],f[i-1][j-v[i]]+w[i])
知道这个式子就好办了,直接套模板ok!
#include
using namespace std;
int n,m,v[30],w[30],f[30][30000];
int main()
{
cin>>n>>m;
for (int i=1;i<=m;i++)
cin>>v[i]>>w[i],w[i]*=v[i];
for(int i=1;i<=m;i++)
for (int j=n;j>=0;j--)
if (j>=v[i])
f[i][j]=max(f[i-1][j],f[i-1][j-v[i]]+w[i]);
else
f[i][j]=f[i-1][j];
cout<
当然还有一个小小的优化,就是可以把这个二维数组变成一维数组,因为大家发现,其实这个max里面始终只有f[i-1]有瓜,所以可以省掉一维,另外,也不用多判断else后面的这一段,因为是直接赋值,一样的,所以省去了。
#include
using namespace std;
int n,m,v[30],w[30],f[30000];
int main()
{
cin>>n>>m;
for (int i=1;i<=m;i++)
cin>>v[i]>>w[i],w[i]*=v[i];
for(int i=1;i<=m;i++)
for (int j=n;j>=v[i];j--)
f[j]=max(f[j],f[j-v[i]]+w[i]);
cout<
这道题目很简单,但是放了暑假之后放飞自我,手感生疏,所以便挑了一些简单的题练练手,顺便呢,写博客其实是想记录一下自己信息学的过程,或许有一天看到了还能回忆当初学信息学的美好时光啊。而且收集下来也是想要提醒自己,不要太粗心了。因为粗心,在签到题上摔跤,痛失了noip普及组的一等奖,也错过了nhoi。一直以来,粗心都是自己长期没有办法去改变的缺点,信息学是,在考试上更是。希望自己能够吸取教训,能一次做好,能不要因为粗心丢分。明明有这个实力,却因为粗心而丢了太多,太不值得了。
离noip2019只剩99天了,加油!!