动归皆背包——那些做过的背包
这里主要是一些简单的背包问题,单独开篇似乎没有必要,就把题目都堆在这里了
题目描述
金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间他自己专用的很宽敞的房间。更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过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]。(其中*为乘号)
请你帮助金明设计一个满足要求的购物单。
输入输出格式
输入格式:
输入的第1行,为两个正整数,用一个空格隔开:
N m
(其中N(<30000)表示总钱数,m(<25)为希望购买物品的个数。)
从第2行到第m+1行,第j行给出了编号为j-1的物品的基本数据,每行有2个非负整数
v p
(其中v表示该物品的价格(v<=10000),p表示该物品的重要度(1~5))
输出格式:
输出只有一个正整数,为不超过总钱数的物品的价格与重要度乘积的总和的最大值(<100000000)。
输入输出样例
输入样例#1:
1000 5 800 2 400 5 300 5 400 3 200 2
输出样例#1:
3900
说明
NOIP 2006 普及组 第二题
【解题思路】
标准01背包,没啥好说的
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 program HappyJinMing; 2 function max(x,y:Longint):longint; 3 begin 4 if x>y then exit(x) else exit(y); 5 end; 6 var 7 f:array[0..25,0..30000] of int64; 8 a,b:array[0..25] of longint; 9 i,j,m,n:Longint; 10 begin 11 read(n,m); 12 for i:=1 to m do read(a[i],b[i]); 13 for i:=1 to m do 14 for j:=n downto 1 do 15 begin 16 if a[i]<=j then f[i,j]:=max(f[i-1,j],f[i-1,j-a[i]]+a[i]*b[i]) 17 else f[i,j]:=f[i-1,j]; 18 end; 19 writeln(f[m,n]); 20 end.
题目背景
uim神犇拿到了uoi的ra(镭牌)后,立刻拉着基友小A到了一家……餐馆,很低端的那种。 uim指着墙上的价目表(太低级了没有菜单),说:“随便点”。
题目描述
不过uim由于买了一些辅(e)辅(ro)书,口袋里只剩M元(M<=10000)。
餐馆虽低端,但是菜品种类不少,有N种(N<=100),第i种卖ai元(ai<=1000)。由于是很低端的餐馆,所以每种菜只有一份。
小A奉行“不把钱吃光不罢休”,所以他点单一定刚好吧uim身上所有钱花完。他想知道有多少种点菜方法。
由于小A肚子太饿,所以最多只能等待1秒。
输入输出格式
输入格式:
第一行是两个数字,表示N和M。
第二行起N个正数ai(可以有相同的数字,每个数字均在1000以内)。
输出格式:
一个正整数,表示点菜方案数。
输入输出样例
输入样例#1:
4 4 1 1 2 2
输出样例#1:
3
【解题思路】
这是属于那种需要统计方案的背包
f[i,j]表示选到第i种时剩余钱数为j可方案数
f[i,j]=f[i-1,j]+f[i-1,j-a[i]];
初始条件是 f[i,0]:=1;
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 program SmallAChoice; 2 var f:array[0..100,0..10000] of longint; 3 a:Array[0..100] of longint; 4 m,n,i,j:longint; 5 begin 6 read(n,m); 7 for i:=1 to n do read(a[i]); 8 for i:=0 to n do 9 begin 10 f[i,0]:=1; 11 end; 12 for i:=1 to n do 13 for j:=m downto 1 do 14 begin 15 if j>=a[i] then 16 17 f[i,j]:=f[i-1,j-a[i]]+f[i-1,j] 18 else f[i,j]:=f[i-1,j]; 19 end; 20 write(f[n,m]) 21 end.
题目描述
辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”
如果你是辰辰,你能完成这个任务吗?
输入输出格式
输入格式:
输入文件medic.in的第一行有两个整数T(1 <= T <= 1000)和M(1 <= M <= 100),用一个空格隔开,T代表总共能够用来采药的时间,M代表山洞里的草药的数目。接下来的M行每行包括两个在1到100之间(包括1和100)的整数,分别表示采摘某株草药的时间和这株草药的价值。
输出格式:
输出文件medic.out包括一行,这一行只包含一个整数,表示在规定的时间内,可以采到的草药的最大总价值。
输入输出样例
输入样例#1:
70 3 71 100 69 1 1 2
输出样例#1:
3
说明
对于30%的数据,M <= 10;
对于全部的数据,M <= 100。
NOIP2005普及组第三题
【解题思路】
这个题好像和第一题并没有什么区别
代码是记忆化写的
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 program gold1; 2 var g,p:array [0..99] of longint;//g,gold缩写 ,表示金矿数 ,p,people缩写,表示人数 3 i,gold,ren,sum:longint;//ren,gold你懂得 4 f:array[0..1000,0..99] of longint;//用于记忆的数组 5 function max(a,b:longint):longint;//求较大值的函数 6 begin 7 if a>b then exit(a) else exit(b); 8 end; 9 function find(n,m:longint):longint; 10 var t:longint; 11 begin 12 if m=0 then//边界条件……当等于0的时候 13 begin 14 if n>=p[0] then 15 begin 16 f[n,0]:=g[0]; 17 find:=g[0]; 18 end 19 else 20 begin 21 f[n,0]:=0; 22 find:=0; 23 end; 24 end; 25 if f[n,m]<>-1 then exit(f[n,m]);//记忆搜索的过程 26 if f[n,m]=-1 then//对未储存的数据进行搜索 27 begin 28 if n>=p[m] then//如果比他大再去求较大值 29 begin 30 t:=max(find(n-p[m],m-1)+g[m],find(n,m-1));//避免重复计算,学会使用中间变量 31 f[n,m]:=t; 32 find:=t; 33 end 34 else//否则直接返回f(n,m-1) 35 begin 36 t:=find(n,m-1); 37 f[n,m]:=t; 38 exit(t); 39 end; 40 end; 41 end; 42 begin 43 read(ren,gold); 44 for i:=0 to gold-1 do 45 begin 46 read(p[i],g[i]); 47 end; 48 fillchar(f,sizeof(f),char(-1));//数组填无效值 49 50 sum:=find(ren,gold-1); 51 writeln(sum); 52 53 end.
题目描述
有一个箱子容量为V(正整数,0<=V<=20000),同时有n个物品(0<n<=30,每个物品有一个体积(正整数)。
要求n个物品中,任取若干个装入箱内,使箱子的剩余空间为最小。
输入输出格式
输入格式:
一个整数,表示箱子容量
一个整数,表示有n个物品
接下来n行,分别表示这n 个物品的各自体积
输出格式:
一个整数,表示箱子剩余空间。
输入输出样例
输入样例#1:
24 6 8 3 12 7 9 7
输出样例#1:
0
说明
NOIp2001普及组 第4题
【解题思路】
这个题和上一个题也没有什么本质上的区别。。。全是01背包算是堆砌水题吗?
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 ar g,p:array [0..30] of longint; 2 i,gold,ren,sum:longint; 3 f:array[0..20000,0..30] of longint; 4 function min(a,b:longint):longint; 5 begin 6 if a>b then exit(b) else exit(a); 7 end; 8 function find(n,m:longint):longint; 9 var t:longint; 10 begin 11 if m=0 then 12 begin 13 if n>=g[0] then 14 begin 15 f[n,0]:=n-g[0]; 16 n:=n-g[0]; 17 18 exit(n); 19 end 20 else 21 begin 22 f[n,0]:=n; 23 find:=n; 24 end; 25 end; 26 if f[n,m]<>-1 then exit(f[n,m]); 27 if f[n,m]=-1 then 28 begin 29 if n>g[m] then 30 begin 31 t:=min(find(n-g[m],m-1),find(n,m-1)); 32 f[n,m]:=t; 33 find:=t; 34 end 35 else 36 begin 37 t:=find(n,m-1); 38 f[n,m]:=t; 39 exit(t); 40 end; 41 end; 42 end; 43 begin 44 read(ren,gold); 45 for i:=0 to gold-1 do 46 begin 47 read(g[i]); 48 end; 49 fillchar(f,sizeof(f),char(-1)); 50 51 sum:=find(ren,gold-1); 52 writeln(sum); 53 54 end.
题目背景
此题为NOIP2005普及组第三题的疯狂版。 此题为纪念LiYuxiang而生。
题目描述
LiYuxiang是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同种类的草药,采每一种都需要一些时间,每一种也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”
如果你是LiYuxiang,你能完成这个任务吗?
此题和原题的不同点:
1.每种采药可以无限制地疯狂采摘。
2.药的种类眼花缭乱,采药时间好长好长啊!师傅等得菊花都谢了!
输入输出格式
输入格式:
输入第一行有两个整数T(1 <= T <= 100000)和M(1 <= M <= 10000),用一个空格隔开,T代表总共能够用来采药的时间,M代表山洞里的草药的数目。接下来的M行每行包括两个在1到10000之间(包括1和10000)的整数,分别表示采摘某种草药的时间和这种草药的价值。
输出格式:
输出一行,这一行只包含一个整数,表示在规定的时间内,可以采到的草药的最大总价值。
输入输出样例
输入样例#1:
70 3 71 100 69 1 1 2
输出样例#1:
140
说明
对于30%的数据,M <= 1000;
对于全部的数据,M <= 10000。
加油LiYuxiang,第一个AC留给你!
【解题思路】
终于。。。终于不是01背包了,这是一个完全背包,把循环顺序改改就好了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 var z,x,i,j,n,m,w,h:longint; 2 a,b:array[1..100000]of longint; 3 f:array[0..100000]of int64; 4 begin 5 readln(z,x); 6 for i:=1 to x do 7 readln(a[i],b[i]); 8 9 for i:=1 to x do 10 for j:=a[i] to z do 11 if f[j]<f[j-a[i]]+b[i] then f[j]:=f[j-a[i]]+b[i]; 12 13 write(f[z]); 14 end.
背包体积为V ,给出N个物品,每个物品占用体积为Vi,价值为Wi,每个物品要么至多取1件,要么至多取mi件(mi > 1) , 要么数量无限 , 在所装物品总体积不超过V的前提下所装物品的价值的和的最大值是多少?
第一行两个数N,V,下面N行每行三个数Vi,Wi,Mi表示每个物品的体积,价值与数量,Mi=1表示至多取一件,Mi>1表示至多取Mi件,Mi=-1表示数量无限
1个数Ans表示所装物品价值的最大值
2 10
3 7 2
2 4 -1
22
对于100%的数据,V <= 200000 , N <= 200
【解题思路】
终于来了一个高难度背包,因为它的数据范围灰常灰常大,我的代码完完全全超时,但是思路是在这的,神马多重背包的二进制拆分之类的都有,虽然他不过
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 program mix; 2 var f:array[0..200000] of longint; 3 v,w,m,s:array[0..200000] of longint; 4 i,j,k,n,v1,p,sum:Longint; 5 begin 6 s[0]:=1; 7 for i:=1 to 30 do s[i]:=s[i-1]*2; 8 read(n,v1); 9 sum:=n; 10 for i:=1 to n do 11 begin 12 read(v[i],w[i],m[i]); 13 if m[i]>1 then 14 begin 15 p:=1; 16 while m[i]>=s[p] do 17 begin 18 inc(sum); 19 v[sum]:=s[p]*v[i]; 20 w[sum]:=s[p]*w[i]; 21 m[sum]:=1; 22 dec(m[i],s[p]); 23 end; 24 if (m[i]>=2) then 25 begin 26 inc(sum); 27 v[sum]:=m[i]*v[i]; 28 w[sum]:=m[i]*w[i]; 29 m[sum]:=1; 30 m[i]:=0; 31 end; 32 end; 33 end; 34 for i:=1 to sum do 35 begin 36 if m[i]=-1 then 37 for j:=v[i] to v1 do 38 begin 39 if f[j]<f[j-v[i]]+w[i] then f[j]:=f[j-v[i]]+w[i]; 40 end 41 else 42 begin 43 for k:=1 to m[i] do 44 for j:=v1 downto k*v[i] do 45 begin 46 if f[j]<f[j-v[i]*k]+w[i]*k then 47 f[j]:=f[j-v[i]*k]+w[i]*k; 48 end; 49 end; 50 end; 51 writeln(f[v1]); 52 end.