动归皆背包——那些做过的背包

这里主要是一些简单的背包问题,单独开篇似乎没有必要,就把题目都堆在这里了

题目描述

金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间他自己专用的很宽敞的房间。更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过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背包,没啥好说的

 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.  
View Code

题目背景

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;  
 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.  
View Code

题目描述

辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。” 

如果你是辰辰,你能完成这个任务吗?

输入输出格式

输入格式:

输入文件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普及组第三题

【解题思路】

这个题好像和第一题并没有什么区别

代码是记忆化写的

 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-135       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.  
View Code

题目描述

有一个箱子容量为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背包算是堆砌水题吗?

 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.  
View Code

题目背景

此题为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背包了,这是一个完全背包,把循环顺序改改就好了。

 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.  
View Code
题目描述 Description

背包体积为V ,给出N个物品,每个物品占用体积为Vi,价值为Wi,每个物品要么至多取1件,要么至多取mi件(mi > 1) , 要么数量无限 , 在所装物品总体积不超过V的前提下所装物品的价值的和的最大值是多少?

输入描述 Input Description

第一行两个数N,V,下面N行每行三个数Vi,Wi,Mi表示每个物品的体积,价值与数量,Mi=1表示至多取一件,Mi>1表示至多取Mi件,Mi=-1表示数量无限

输出描述 Output Description

1个数Ans表示所装物品价值的最大值

样例输入 Sample Input

2 10

3 7 2

2 4 -1

样例输出 Sample Output

22

数据范围及提示 Data Size & Hint

对于100%的数据,V <= 200000 , N <= 200

【解题思路】

终于来了一个高难度背包,因为它的数据范围灰常灰常大,我的代码完完全全超时,但是思路是在这的,神马多重背包的二进制拆分之类的都有,虽然他不过

 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.
View Code

 

posted @ 2015-08-21 07:48  Alisahhh  阅读(342)  评论(0编辑  收藏  举报