完全背包专题训练(Pascal)

合集下载

0-1背包问题与完全背包问题C++实现动态规划

0-1背包问题与完全背包问题C++实现动态规划

0-1背包问题与完全背包问题C++实现动态规划今天看了看背包九讲,⾃⼰写了下0-1背包和完全背包王晓东《计算机算法分析与设计》上⾯给出的C++实现⽐较繁琐,相⽐⽽⾔这个版本更加简明给出了测试数据0-1背包问题C++实现的最⼤价值Sample Input 3 34 57 9Sample Output 120 1 0 1*/#include<stdio.h>#include<string.h>int c[20][1000];//c[k][y]为只允许装前k 种物品,背包总重量不超过y 的最⼤价值int inumber[21][1000];//inumber[k][u]为只允许装前K 种物品,背包总重量不超过y 时得到最⼤价值时使⽤的背包的最⼤标号int w[21],p[21];int knapsack(int m,int n){ int i,j; for(i=1;i<n+1;i++) scanf("%d%d",&w[i],&p[i]); memset(c,0,sizeof(c)); memset(inumber,0,sizeo f(inumber)); for(j=1;j<m+1;j++){ c[1][j]=j/w[1]*p[1]; } for(i=1;i<n+1;i++){ for(j=1;j<m+1;j++){ if(j >= w[i]){ if(p[i]+c[i-1][j-w[i]]>=c[i-1][j]){ c[i][j]=p[i]+c[i-1][j-w[i]]; inumber[i][j]=i; } else{ c[i][j]=c[i-1][j]; inumber[i][j]=inumber[i-1][j]; } } else{ c[i][j]=c[i-1][j]; inumber[i][j]=inumber[i-1][j]; } }题的最⼤价值Sample Input10 42 13 34 51 9Sample Output900 0 0 10*/#include<stdio.h>#include<string.h>int c[20][1000];//c[k][y]为只允许装前k 种物品,背包总重量不超过y 的最⼤价值int inumber[21][1000];//inumber[k][u]为只允许装前K 种物品,h 背包总重量不超过y 时得到最⼤价值时使⽤的背包的最⼤标号int w[21],p[21];int knapsack(int m,int n){int i,j;for(i=1;i<n+1;i++)scanf("%d%d",&w[i],&p[i]);memset(c,0,sizeof(c));memset(inumber,0,sizeof(inumber));for(j=1;j<m+1;j++){c[1][j]=j/w[1]*p[1];}for(i=1;i<n+1;i++){for(j=1;j<m+1;j++){if(j >= w[i]){if(p[i]+c[i][j-w[i]]>=c[i-1][j]){//和0-1背包相⽐只是将c[i-1][j-w[i]]写成了c[i][j-w[i]],因为完全背包问题中每件物品有⽆限个c[i][j]=p[i]+c[i][j-w[i]];inumber[i][j]=i;}else{c[i][j]=c[i-1][j];inumber[i][j]=inumber[i-1][j];}。

理学背包问题详解

理学背包问题详解
9
0 1 2 3 4 5 6 7 8 9 10
000000000000
x1=1
w1=2 v1=6 1 0 0 6 6 6 6 6 6 6 6 6
x2=1
w2=2 v2=3 2 0 0 6 6 9 9 9 9 9 9 9
x3=0
w3=6 v3=5 3 0 0 6 6 9 9 9 9 11 11 14
可用动态规划算法求解。
3
其他类型背包问题
完全背包问题(0/1):
有N种物品和一个容量为V的背包,每种物品都有 无限件可用。第i种物品的费用是c[i],价值是w[i]。 求解将哪些物品装入背包可使这些物品的费用总和 不超过背包容量,且价值总和最大。
多重背包问题
有N种物品和一个容量为V的背包。第i种物品最多 有n[i]件可用,每件费用是c[i],价值是w[i]。求解 将哪些物品装入背包可使这些物品的费用总和不超 过背包容量,且价值总和最大。
{// 计算x
for (int i=1; i<n; i++)
if (m[i][c]==m[i+1][c])
x[i]=0;
else
{
x[i]=1;
c-=w[i];
}
x[n]=(m[n][c])?1:0;
}
11
算法改进
由m(i,j)的递归式容易证明,在一般情况下,对每一个确定的 i(1≤i≤n),函数m(i,j)是关于变量j的阶梯状单调不减函数。跳跃 点是这一类函数的描述特征。在一般情况下,函数m(i,j)由其 全部跳跃点唯一确定。如图所示。
(7,7)
(6,6) (4,5)
(4,5)(6,6)
(0,
0)
(2,
(3,2) 1)

0-1背包问题详解二(完全背包问题)

0-1背包问题详解二(完全背包问题)

0-1背包问题详解⼆(完全背包问题)问题描述给定n种物品和⼀个背包。

物品i的重量是w(i),其价值为v(i),背包的容量为c(即最多能够装c重量的物品)。

这n种物品可以重复放置(这是与普通背包问题的不同之处)。

输⼊n=5,c=6.物品容量和价值分别为:2 62 36 55 44 6最后输出时:18问题求解:f[i][v]=max{f[i-1][v-k*c[i]]+k*w[i]|0<=k*c[i]<=v}似乎利⽤上⾯那个公式就可以很好的求出解。

这⾥给出另外⼀组公式,该公式和上⽂的公式是⼀样的,只是第⼆个for语句的倒过来。

for i=1..Nfor v=0..Vf[v]=max{f[v],f[v-cost]+weight}为什么这样⼀改就可⾏呢?⾸先想想为什么上⽂中要按照v=V..0的逆序来循环。

这是因为要保证第i次循环中的状态f[i][v]是由状态f[i-1][v-c[i]]递推⽽来。

换句话说,这正是为了保证每件物品只选⼀次,保证在考虑“选⼊第i件物品”这件策略时,依据的是⼀个绝⽆已经选⼊第i件物品的⼦结果f[i-1][v-c[i]]。

⽽现在完全背包的特点恰是每种物品可选⽆限件,所以在考虑“加选⼀件第i种物品”这种策略时,却正需要⼀个可能已选⼊第i种物品的⼦结果f[i][vc[i]],所以就可以并且必须采⽤v=0..V的顺序循环。

这就是这个简单的程序为何成⽴的道理。

1void compelteKnapsack(){2int c,n;3 cout<<"请输⼊最⼤容量,⼩于100"<<endl;4 cin>>c;5 cout<<"请输⼊背包个数"<<endl;6 cin>>n;7 cout<<"请输⼊各个背包重量和价值"<<endl;8for(int i=1;i<=n;i++){9 cin>>w[i]>>v[i];10 }11for(int i=0;i<=n;i++)12 p[i]=0;13for(int i=1;i<=n;i++)14for(int j=w[i];j<=c;j++)15 p[j]=max(p[j],p[j-w[i]]+v[i]);16 cout<<"结果是"<<p[c]<<endl;17 }View Code版权所有,欢迎转载,但是转载请注明出处:。

Pascal经典算法-背包问题析ppt课件

Pascal经典算法-背包问题析ppt课件
begin a[i]:=j;//标识该物品的形状 m:=m-a[i]*j;//剩余空间变化 try[i+1];//下一个物体选择 m:=m-a[i]*j;//剩余空间变化 a[i]:=0; end; End.
递归概念
我们可以用choose(I,z)来表示后i个物品在只剩下v个体积的空间中取的最 大价值
所谓的背包问题,可以描画如下: 一个小偷打劫一个保险箱,发现柜子里有N
个不同大小与价值的物品,但小偷只需一 个容积为M的背包来装东西,背包问题就 是要找出一个小偷选择所偷物品的组合, 以使偷走的物品总价值最大。我们标识每 个物品的价为VI,大小是ZI
算法描画
对于0/1背包相关的问题我们有多种方法可 以处理
end;
end;
0/1背包问题的分析
该背包问题的目的在于求最优解,所以我们要用 回溯的方法将一切的解求出来,逐一比较求最优 秀的解;
对于每个节点的扩展只需两种类能够要不取,要 不不取,所以该搜索树为一个N层的二叉树。
解空间的长度是<=n。 解空间的组织方式是一棵2叉树,一个可行的解就
是从根节点到叶子节点的一条途径。每个解为一 个长度不超越N的0/1代码序列 控制战略那么是前面的选择没有超越背包的容量。
end;
for i:=算符最小值 to 算符最大值 do
begin
算符i作用于生成stack[k-1]产生子形状stack[k];
if stack[k]满足约束条件 then make(k+1);{假设不满足,那么经过for循环换一个算
算符扩展。注:假设在扩展stack[k].state时运用过全局变量,那么应插入假设干条语句,恢
二、回溯的通用描画算法
program 程序名;

背包问题(3):完全背包

背包问题(3):完全背包

背包问题(3):完全背包完全背包也是⼀种基本的背包问题模型,其基本特点是:每种物品可以放⽆限多次。

这个问题⾮常类似于0/1背包问题,所不同的是每种物品有⽆限件。

也就是从每种物品的⾓度考虑,与它相关的策略已并⾮取或不取两种,⽽是有取0件、取1件、取2件……等很多种。

完全背包问题的⼀般描述为:有N个物品,第i个物品的重量与价值分别为W[i]与P[i]。

背包容量为V,问在每个物品有⽆限个(物品必须保持完整)的情况下,如何让背包装⼊的物品具有更⼤的价值总和。

其⼀般解题思路为:令 f[i][j] 表⽰从编号1~i的物品中挑选任意数量的任意物品放⼊容量为j的背包中得到的最⼤价值,那么有f[i][j]=max { f[i−1][j],f[i−1][j−k∗W[i]]+k∗P[i] } (0≤k && k∗W[i]≤j)编写代码时,可采⽤如下的循环。

for ( i=1;i<=N;i++) // 依次对每个物品进⾏处理for (j=1;j<=V;j++)for (k=1; k<=V/W[i];k++) // 物品最多只能放多少件{If (k*W[i]<=j)f[i][j]=max(f[i-1][j],f[i-1][j-k*W[i]]+k*P[i]);elsef[i][j]=f[i-1][j];}所求的最优值为f[N][V]。

同样完全背包也可以进⾏空间优化,将⼆维数组优化为⼀维数组,即f[j]=max { f[j],f[j−k∗W[i]]+k∗P[i] } (0≤k && k∗W[i]≤j)编写代码时,⼀般采⽤如下的⼆重循环。

for (i=1;i<=N;i++) // 装⼊背包的物品个数为Nfor ( j=W[i];j<=V;j++) // 完全背包按由⼩到⼤顺序枚举重量f[j]=max(f[j],f[j-W[i]]+P[i]); // 状态转移所求的最优值为f[V]。

pascal常用算法代码

pascal常用算法代码

//求无向图割顶的算法,割顶:若在图的dfs树上,i 存在儿子节点 s ,使得 s 及 s 的所有子孙的后向边不指向 i 的祖先(可以指向i),输出的是一个点I,尝试写成过程,然后找到其应用
ary(多进制2-16转十进制).pas
program ary;
var a:array [1..10000] of longint;
program ary;
var a:array [1..10000] of longint;
k:array [1..10000] of char;
s,j,b,t:longint;
begin
readln(s);
readln(b);
while s<>0 do
begin
'B':a[j]:=11;
'C':a[j]:=12;
'D':a[j]:=13;
'E':a[j]:=14;
'F':a[j]:=15;
end;
inc(j);
end;
for i:=1 to j do
if a[i]>=b then
for k:=1 to n do if (i<>k)and(j<>k)then
if (a[i,j]<>maxlongint)and(d[i]<>maxlongint)and(d[j]>d[i]+a[i,j])then
d[j]:=d[i]+a[i,j];
for i:=1 to n do
begin
case a[j] of

背包问题(一个以及无限个)

背包问题(一个以及无限个)

背包问题(⼀个以及⽆限个)题⽬说明:假設有⼀個背包的負重最多可達8公⽄,⽽希望在背包中裝⼊負重範圍內可得之總價物品,假設是⽔果好了,⽔果的編號、單價與重量如下所⽰:0李⼦4KG NT$45001蘋果5KG NT$57002橘⼦2KG NT$22503草莓1KG NT$11004甜⽠6KG NT$6700⾸先,是每种⽔果都只有⼀个的算法。

#include <stdio.h>#include <stdlib.h>int getMax(int fruitP[], int fruitW[], int form[][9], int fruitNum, int bagW){int i, j;for(i = 1; i <= fruitNum; i++){for(j = 1; j <= bagW; j++){if(j - fruitW[i] < 0){form[i][j] = form[i - 1][j];}else if(form[i - 1][j - fruitW[i]] + fruitP[i] > form[i - 1][j]){form[i][j] = form[i - 1][j - fruitW[i]] + fruitP[i];}else{form[i][j] = form[i - 1][j];}}}}print(int form[][9], int h, int l){int i, j;for(i = 0; i < l; i++) printf("%.5d ", i);printf("\n");for(i = 0; i < h; i++){for(j = 0; j < l; j++){printf("%.5d ", form[i][j]);}printf("\n");}}main(){int fruitP[6] = {0, 450, 570, 225, 110, 670};int fruitW[6] = {0, 4, 5, 2, 1, 6};int form[6][9] = {0};getMax(fruitP, fruitW, form, 5, 8);print(form, 6, 9);}如果⽔果是⽆限个则可以这么写:#include <stdio.h>#include <stdlib.h>int getMax(int fruitP[], int fruitW[], int form[][9], int fruitNum, int bagW){int i, j;for(i = 1; i <= fruitNum; i++){for(j = 1; j <= bagW; j++){if(j - fruitW[i] < 0){form[i][j] = form[i - 1][j];}else if(form[i - 1][j - fruitW[i]] + fruitP[i] > form[i - 1][j]){if(form[i - 1][j - fruitW[i]] + fruitP[i] > form[i][j - fruitW[i]] + fruitP[i])form[i][j] = form[i - 1][j - fruitW[i]] + fruitP[i];else form[i][j] = form[i][j - fruitW[i]] + fruitP[i];}else{if(form[i][j - fruitW[i]] + fruitP[i] < form[i - 1][j])form[i][j] = form[i - 1][j];else form[i][j] = form[i][j - fruitW[i]] + fruitP[i];}}}}print(int form[][9], int h, int l){int i, j;for(i = 0; i < l; i++) printf("%.5d ", i);printf("\n");for(i = 0; i < h; i++){for(j = 0; j < l; j++){printf("%.5d ", form[i][j]);}printf("\n");}}main(){int fruitP[6] = {0, 450, 570, 225, 110, 670};int fruitW[6] = {0, 4, 5, 2, 1, 6};int form[6][9] = {0};getMax(fruitP, fruitW, form, 5, 8);print(form, 6, 9);}⼀个和⽆限个的差别在于,在作⽐较的时候不仅跟上⼀⾏⽐较,还要跟当前⾏作⽐较,较⼤者置换即可。

完全背包问题(LeetCode第322、518题)

完全背包问题(LeetCode第322、518题)

完全背包问题(LeetCode第322、518题)题⽬:518题给定不同⾯额的硬币和⼀个总⾦额。

写出函数来计算可以凑成总⾦额的硬币组合数。

假设每⼀种⾯额的硬币有⽆限个。

分析:对于这种动态规划问题,我们必须弄清楚这⼏个问题:状态数组的含义、状态转移⽅程、边界条件以及状态数组索引的选择范围。

⾸先我们来定义⼀个状态数组,根据题⽬要求我们知道最终的⽬标是要求那么⼦问题就是在前i种硬币的选择范围下,凑成当前所要求的⾦额的组合数⽬。

所以状态转移数组就是⼀个⼆维数组:dp[i][j]。

dp[i][j]:前i中硬币,在总⾦额为j的情况下,硬币的组合数。

然后来分析状态转移⽅程: 对于当前访问的⾦币coin: 如果 coin > j,那么当前⾦币不能放⼊组合,所以dp[i][j] = dp[i-1][j] 如果 coin <= j,那么当前⾦币可以考虑放⼊组合,⽽且放⼊⼏个也是需要考虑的,所以因为我们要求的是组合数,所以任何组合都要考虑,所以dp[i][j] = sum(dp[i-1][j-k*coin]),k * coin <= j边界条件: (1)有⾦币,但是总额为0时,那么组合数应为1, (2)⽆⾦币,也⽆总额,组合数也为1; (3)总额⼤于0,⾦币为⽆,那么没有组合能够凑成总额,所以组合数为0所以最终的实现代码如下:public int change(int amount, int[] coins) {if (amount>0 && coins.length==0)return 0;int n = coins.length;int[][] dp = new int[n+1][amount+1];dp[0][0] = 1;for (int i = 1; i <= n; i++) {for (int j = 0; j <= amount; j++) {if (coins[i-1] > j)dp[i][j] = dp[i-1][j];else {for (int k = 0; k * coins[i-1]<= j; k++) {dp[i][j] += dp[i-1][j-k*coins[i-1]];}}}}return dp[n][amount];}优化⼀:进⼀步分析dp[i][j],发现它的值依赖于两种情况,对于第i个⾦币,是否加⼊背包? (1)不加⼊,那么dp[i][j] = dp[i-1][j]; (2)加⼊,那么当前背包容量变成了j-coin,但是由于⾦币是⽆限的所以对于硬币的选择范围依旧是前i个⾦币。

背包问题习题

背包问题习题

1、0/1背包
【问题描述】
一个旅行者有一个最多能装m公斤物品的背包,现在有n件物品,它们的重量分别是w1,w2,…,wn,它们的价值分别为c1,c2,…cn。

若每种物品只有一件,求旅行者能获得的最大总价值。

【输入格式】
第一行:两个整数m(背包容量,m≤200)和n(物品数量,n≤30);
第二~n+1行:每行两个整数wi,ci,表示每个物品的重量和价值。

【输出格式】
一个数据,表示最大总价值。

【输入样例】
10 4
2 1
3 3
4 5
7 9
【输出样例】
12
2、完全背包问题
【问题描述】
设有n中物品,每种物品有一个重量及一个价值。

但每种物品的数量是无限的,同时有一个背包,最大载重量为m,今从n种物品中选取若干件(同一物品可以多次选取),使其重量的和小于等于m,而价值的和为最大。

【输入格式】
第一行:两个整数,m(背包容量,m≤200)和(物品数量,n≤30);
第二~n+1行:每行两个整数wi,ui,表示每个物品的重量和价值。

【输出格式】
仅一行,一个数,表示最大总价值。

【输入样例】
10 4
2 1
3 3
4 5
7 9
【输出样例】
max=12。

背包问题:0-1背包、完全背包和多重背包

背包问题:0-1背包、完全背包和多重背包

背包问题:0-1背包、完全背包和多重背包背包问题泛指以下这⼀种问题:给定⼀组有固定价值和固定重量的物品,以及⼀个已知最⼤承重量的背包,求在不超过背包最⼤承重量的前提下,能放进背包⾥⾯的物品的最⼤总价值。

这⼀类问题是典型的使⽤动态规划解决的问题,我们可以把背包问题分成3种不同的⼦问题:0-1背包问题、完全背包和多重背包问题。

下⾯对这三种问题分别进⾏讨论。

1.0-1背包问题0-1背包问题是指每⼀种物品都只有⼀件,可以选择放或者不放。

现在假设有n件物品,背包承重为m。

对于这种问题,我们可以采⽤⼀个⼆维数组去解决:f[i][j],其中i代表加⼊背包的是前i件物品,j表⽰背包的承重,f[i][j]表⽰当前状态下能放进背包⾥⾯的物品的最⼤总价值。

那么,f[n][m]就是我们的最终结果了。

采⽤动态规划,必须要知道初始状态和状态转移⽅程。

初始状态很容易就能知道,那么状态转移⽅程如何求呢?对于⼀件物品,我们有放进或者不放进背包两种选择:(1)假如我们放进背包,f[i][j] = f[i - 1][j - weight[i]] + value[i],这⾥的f[i - 1][j - weight[i]] + value[i]应该这么理解:在没放这件物品之前的状态值加上要放进去这件物品的价值。

⽽对于f[i - 1][j - weight[i]]这部分,i - 1很容易理解,关键是 j - weight[i]这⾥,我们要明⽩:要把这件物品放进背包,就得在背包⾥⾯预留这⼀部分空间。

(2)假如我们不放进背包,f[i][j] = f[i - 1][j],这个很容易理解。

因此,我们的状态转移⽅程就是:f[i][j] = max(f[i][j] = f[i - 1][j] , f[i - 1][j - weight[i]] + value[i])当然,还有⼀种特殊的情况,就是背包放不下当前这⼀件物品,这种情况下f[i][j] = f[i - 1][j]。

动态规划-01背包问题-01背包习题(背包问题2)

动态规划-01背包问题-01背包习题(背包问题2)

动态规划-01背包问题-01背包习题(背包问题2)背包问题2描述n个物品,每个物品有⼀个体积v和价值w。

现在你要回答,把⼀个物品丢弃后,剩下的物品装进⼀个⼤⼩为V的背包⾥能得到的最⼤价值是多少。

输⼊输⼊的第⼀⾏包含⼀个正整数n(n ≤ 5000)。

接下来n⾏,每⾏包含两个正整数v和w(v,w ≤ 5000),分别表⽰⼀个物品的体积和价值。

接下来⼀⾏包含⼀个正整数q(q ≤ 5000),表⽰询问个数。

接下来q⾏,每⾏包含两个正整数V和x(V ≤ 5000,x ≤ n),表⽰询问将物品x丢弃以后剩下的物品装进⼀个⼤⼩为V的背包能得到的最⼤价值。

输出输出q⾏,每⾏包含⼀个整数,表⽰询问的答案。

样例输⼊33 52 21 233 13 23 3样例输出455样例解释有3个物品,第⼀个物品的体积为3、价值为5,第⼆个物品体积为2、价值为2,第三个物品体积为1、价值为2。

有3个询问:第⼀个询问是问去掉1物品后剩下的2、3物品填进⼀个⼤⼩为3的背包能得到的最⼤价值。

显然2、3物品都是可以放进背包的,所以最⼤价值为2+2=4。

第⼆个询问是问去掉2物品后剩下的1、3物品填进⼀个⼤⼩为3的背包能得到的最⼤价值。

若我们填3物品,我们只能得到价值2;若我们填1物品,则可以得到价值5。

所以最⼤价值为5。

第三个询问我们同样也是填1物品,最⼤价值为5。

限制对于30%的数据,n,q,v,V,w ≤ 10;对于50%的数据,n,q,v,V,w ≤ 200。

时间:10 sec空间:512 MB--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------思路这是⼀个01背包问题的扩展习题。

完全背包问题和0-1背包问题

完全背包问题和0-1背包问题

1.实验目的(结出本次实验所涉及并要求掌握的知识点)利用动态规划策略解决0-1背包和完全背包问题2.实验内容(结出实验内容具体描述)(1)0-1 Knapsack Problem和Unbounded Knapsack Problem的算法进行实现(2)对0-1Knapsack Problem的算法进行空间优化,使其空间复杂度达到O(W)3.算法描述及实验步骤(用适当的形式表达算法设计思想与算法实现步骤)1. 二维数组的0-1背包空间O(nW)int record[100][100]; // 0-1 背包的二维表void ZO_knapsack_1(int num,int room){// 针对每一个物品进行筛选,看他是否是构成最终max的组成int i,j;for(i=0;i<=num;i++)for(j=0;j<=room;j++)record[i][j]=0; // 初始化record表for(i=1;i<=num;i++){for(j=0;j<=room;j++){if(a[i][0]>j)record[i][j]=record[i-1][j];else{if(record[i-1][j-a[i][0]]+a[i][1]>record[i-1][j])record[i][j]=record[i-1][j-a[i][0]]+a[i][1];elserecord[i][j]=record[i-1][j];}}}}int arry[100]; // 一维记录表int carry[100]; // 是否拿走该物品记录void ZO_knapsack_2(int num,int room){int i,j;for(i=0;i<=num;i++)arry[i]=0; // 初始化arry表for(i=1;i<=num;i++){for(j=room;j>=a[i][0];j--){ //逆序记录if(arry[j-a[i][0]]+a[i][1]>arry[j])arry[j]=arry[j-a[i][0]]+a[i][1];}}3. 一维数组实现完全背包空间:O(W)void UNbounded(int num,int room){int i,j;for(i=0;i<=num;i++)arry[i]=0; // 初始化arry表for(i=1;i<=num;i++){for(j=a[i][0];j<=room;j++){ //顺序记录if(arry[j-a[i][0]]+a[i][1]>arry[j])arry[j]=arry[j-a[i][0]]+a[i][1];}}}4.调试过程及运行结果(详细记录在调试过程中出现的问题及解决方法。

01背包经典变形题

01背包经典变形题

01背包经典变形题
有以下几个经典的01背包变形题:
1. 完全背包问题
完全背包问题是指每种物品都有无限个可以选择,可以选择多次放入背包。

与01背包问题类似,但需要修改状态转移方程。

状态转移方程:dp[i][j] = max(dp[i-1][j],dp[i][j-w[i]]+v[i])
2. 多重背包问题
多重背包问题是指每种物品都有一定的个数限制,限制个数大于1。

需要修改状态转移方程和循环遍历次数。

状态转移方程:dp[i][j] = max(dp[i-1][j],dp[i][j-k*w[i]]+k*v[i]),其中k代表第i种物品的个数限制。

3. 混合背包问题
混合背包问题是指既有物品个数限制大于1的物品,也有物品个数限制为1的物品。

需要综合01背包、完全背包和多重背
包的思路求解。

4. 分组背包问题
分组背包问题是指将物品分为若干组,每组物品只能选择一个。

需要修改状态转移方程和循环遍历次数,遍历的次数基于组号遍历。

状态转移方程:dp[i][j] = max(dp[i-1][j],dp[i][j-w[i][k]]+v[i][k]),其中k代表第i组中的第k个物品。

这些变形题在01背包问题的基础上进行了一些修改,需要根据具体问题进行相应的调整。

背包问题

背包问题

背包问题常州一中林厚从背包问题是信息学奥赛中的经典问题。

背包问题可以分为0-1背包和部分背包两种类型,0-1背包还可以再分为有限背包和无限背包(完全背包)。

背包问题的求解涉及到贪心、递归、递推、动态规划、搜索等多种算法。

熟练掌握各种背包问题及其变形试题的解法,是信息学奥赛选手从入门走向提高的必经之路。

先简单归纳一下涉及到的这几种重要算法:1、贪心:贪心法可以归纳为“每步取优”。

假设你的程序要走1~n共n步,则你只要保证在第i步(i=1..n)时走出的这一步是最优的。

所以,贪心法不是穷举,而只是一种每步都取优的走法。

但由于目光短浅,不考虑整体和全局,所以“步步最优”并不能保证最后的结果最优。

比如经典的“两头取数”问题、“n个整数连接成最大数”问题、“删数”问题等。

2、递归:递归算法可以归纳为将问题“由大化小”。

也就是将一个大问题分解为若干个“性质相同”的子问题,求解的的过程,一般是通过“函数的递归调用”,不断将大问题逐步细化、直至元问题(边界情况),最后通过递归函数的自动返回得到问题的解。

递归算法的关键是递归函数的构造,它的效率往往比较低,原因在于大量的“冗余”计算。

比如经典的“斐波那挈数列”问题,在递归实现时效率极低,存在着大量的冗余计算,可以采用“记忆化”的方法优化。

3、递推:递推问题往往有一个“递推公式”,其实和“递归公式”差不多,但是出发点不一样,递归的思想是“要想求什么就要先求出什么”。

而递推是从问题的边界情况(初始状态)出发,一步步往下走,直到走完n步,判断最后的解。

由于其中的每一步并不知道当前一步的哪一个值对后面的步骤有用,所以只能把所有情况(一步的所有走法)全部计算出来,也造成了很多的“冗余计算”。

时间上往往没有太多的优化余地,但空间上经常利用“滚动数组”等方式,把空间复杂度由O(n2)降到O(2n)。

比如经典的“杨辉三角形”问题、“判断n是否是斐波那挈数”问题等。

4、动态规划:本质上是一种克服了“冗余”的“递归”算法。

背包学习之背包九讲

背包学习之背包九讲

背包学习之背包九讲做了⼀些icpc题⽬,感受到动态规划的重要性,在此学习背包参考⾄博客背包九讲01背包问题完全背包问题多重背包问题混合背包问题⼆维费⽤的背包问题分组背包问题有依赖的背包问题背包问题求⽅案数求背包问题的具体⽅案01完全背包:问题:n个物品(体积和价值分别为v[i],w[i])和⼀个体积为V的背包,求背包装到的最⼤价值状态数组:dp[i][j]为选前i个所⽤体积为j的最⼤价值for(int i=1;i<=n;++i)for(int j=1;j<=V;++j)dp[i][j]=max(dp[i][j],dp[i-1][j-v[i]]+w[i]);滚动数组优化:for(int i=1;i<=n;++i)for(int j=V;j>=vi;--j)dp[j]=max(dp[j],dp[j-v[i]])+w[i]完全背包:问题:n种物品(每种⽆限个,体积和价值分别为v[i],w[i])和⼀个体积为V的背包,求背包最⼤价值状态数组:dp[i][j]为选到前i种所⽤体积为j的最⼤价值for(int i=1;i<=n;++i)for(int j=0;j<=V;++j)for(int k=1;k*v[i]<=j;++k)dp[i][j]=max(dp[i][j],dp[i-1][j-k*v[i]]+k*w[i]);时间优化for(int i=1;i<=n;++i)for(int j=0;j<=V;++j){dp[i][j]=dp[i-1][j];if(j>=v[i]) dp[i][j]=max(dp[i][j],dp[i][j-v[i]]+w[i]);}滚动数组空间优化for(int i=1;i<=n;++i)for(int j=V;j>=v[i];--j)dp[j]=max(dp[j],dp[j-v[i]]+w[i]);多重背包问题:n种物品(每种有限个,数量,体积和价值分别为s[i],v[i],w[i])和⼀个体积为V的背包,求背包最⼤价值状态数组:dp[i][j]为选到前i种所⽤体积为j的最⼤价值for(int i=1;i<=n;++i)for(int j=0;j<=V;++j)for(int k=0;k*v[i]<=j&&k<=s[i];++k)dp[i][j]=max(dp[i][j],dp[i-1][j-k*v[i]]+k*w[i]);空间优化for(int i=1;i<=n;++i)for(int j=V;j>=0;--j)for(int k=0;k*v[i]<=j&&k<=s[i];++k)dp[j]=max(dp[j],dp[j-k*v[i]]+k*w[i]);⼆进制时间优化将数量为s[i]的物品分成s[i]=1+2+4+8+...+x,然后跑01背包,复杂度由n3优化为n2logn代码略多重背包问题:既有⽆限个的,⼜有单个的,⼜有多个的,仍然是背包V,求最⼤价值单个的可看成多重背包的特殊状况,然后有限个和⽆限个分别讨论直接上⼀维:dp[j]代表⽤j体积装到的最⼤价值for(int i=1;i<=n;++i) cin>>v[i]>>w[i]>>s[i];//当s[i]=0时,为⽆限个for(int i=1;i<=n;++i){if(s[i]==0){for(int j=V;j>=v[i];--j) dp[j]=max(dp[j],dp[j-v[i]]+w[i]);}else{for(int k=1;k<=s[i];s[i]-=k,k*=2){for(int k=V;j>=k*v[i];--j)dp[j]=max(dp[j],dp[j-k*v[i]]+w[i]);}if(!s[i]) continue;for(int j=V;j>=s[i]*v[i];j--)dp[j]=max(dp[j],dp[j-s[i]*v[i]]+s[i]*w[i]);}}⼆维费⽤的背包问题问题:n个物品(体积,重量和价值分别为v[i],m[i],w[i])和⼀个体积为V,限重为M的背包,求背包最⼤价值问题:n种物品(每种有限个,数量,体积和价值分别为s[i],v[i],w[i])和⼀个体积为V的背包,求背包最⼤价值加⼀维就⾏了状态数组:dp[i][j]代表体积为i,载重为j时的最⼤价值for(int i=1;i<=n;++i)for(int j=V;j>=v[i];j--)for(int k=M;k>=m[i];--k)dp[j][k]=max(dp[j][k],dp[j-v[i]][k-m[i]]+w[i]);分组背包问题:n堆物品,每堆s[i]个,每个体积和价值为v[i],w[i],和⼀个体积为V背包,每堆物品只能选⼀个,求最⼤价值分组背包看起来没什么⽤,实际上是各种DP题的热门考点,特别是树形DP⼀维状态:dp[j]代表⽤j体积的最⼤价值for(int i=1;i<=n;++i)for(int j=V;j>=0;--j)for(int k=1;k<=s[i];++k)if(j>=v[k])dp[j]=max(dp[j],dp[j-v[k]]+w[k]);例题:,有依赖的背包问题问题:n个物体之间存在着依赖关系,例如依赖关系是⼀棵树,选择⼀个节点需要选择其⽗亲节点实质上就是⼀道⾚果果的树形DP状态⽅程:dp[x][y] 代表x节点选了体积为y的最⼤价值void dfs(int s){for(auto v:edge[s]){dfs(v);for(int j=V;j>=v[s];--j)for(int k=0;k<=j-v[s];++k)dp[s][j]=max(dp[s][j],dp[s][j-k]+dp[v][k]);}}第⼆类问题:n节点数选m点,选⼀个点必须选⽗节点,使总价值最⼤状态⽅程:dp[x][i] 代表x节点选择了i个节点的最⼤价值,答案就是dp[1][m]void dfs(int s){for(auto v:edge[s]){dfs(v);for(int i=m;i>=1;--i)for(int j=0;j<i;++j)dp[s][i]=max(dp[s][i],dp[s][i-j]+dp[v][j]);}}背包问题求⽅案数问题:n个物品(体积和价值分别为v[i],w[i])和⼀个体积为V的背包,求选取价值达到最⼤的⽅案数只需在原来的基础上加⼀个计数的数组即可for(int i=1;i<=n;++i)for(int j=V;j>=v[i];--j){if(dp[j-v[i]]+w[i]>dp[j]){dp[j]=dp[j-v[i]]+w[i];num[j]=num[j-v[i]];}else if(dp[j-v[i]]+w[i]==dp[j])num[j]+=num[j-v[i]];}背包问题求出具体⽅案问题:n个物品(体积和价值分别为v[i],w[i])和⼀个体积为V的背包,求选取价值达到最⼤的⽅案for(int i=1;i<=n;++i)for(int j=V;j>=vi;--j)dp[j]=max(dp[j],dp[j-v[i]])+w[i];int val=V;for(int i=n;i>=1;--i)if(val-v[i]>=0&&dp[val-v[i]]+w[i]==dp[val])cout<<i<<" ";如果题⽬有要求字典序最⼩,那求解01背包的时候应当倒着求。

背包九讲(DD)

背包九讲(DD)

背包问题九讲目录第一讲 01背包问题第二讲完全背包问题第三讲多重背包问题第四讲混合三种背包问题第五讲二维费用的背包问题第六讲分组的背包问题第七讲有依赖的背包问题第八讲泛化物品第九讲背包问题问法的变化附:USACO中的背包问题前言本篇文章是我(dd_engi)正在进行中的一个雄心勃勃的写作计划的一部分,这个计划的内容是写作一份较为完善的NOIP难度的动态规划总结,名为《解动态规划题的基本思考方式》。

现在你看到的是这个写作计划最先发布的一部分。

背包问题是一个经典的动态规划模型。

它既简单形象容易理解,又在某种程度上能够揭示动态规划的本质,故不少教材都把它作为动态规划部分的第一道例题,我也将它放在我的写作计划的第一部分。

读本文最重要的是思考。

因为我的语言和写作方式向来不以易于理解为长,思路也偶有跳跃的地方,后面更有需要大量思考才能理解的比较抽象的内容。

更重要的是:不大量思考,绝对不可能学好动态规划这一信息学奥赛中最精致的部分。

你现在看到的是本文的1.0正式版。

我会长期维护这份文本,把大家的意见和建议融入其中,也会不断加入我在OI学习以及将来可能的ACM-ICPC的征程中得到的新的心得。

但目前本文还没有一个固定的发布页面,想了解本文是否有更新版本发布,可以在OIBH论坛中以“背包问题九讲”为关键字搜索贴子,每次比较重大的版本更新都会在这里发贴公布。

目录第一讲 01背包问题这是最基本的背包问题,每个物品最多只能放一次。

第二讲完全背包问题第二个基本的背包问题模型,每种物品可以放无限多次。

第三讲多重背包问题每种物品有一个固定的次数上限。

第四讲混合三种背包问题将前面三种简单的问题叠加成较复杂的问题。

第五讲二维费用的背包问题一个简单的常见扩展。

第六讲分组的背包问题一种题目类型,也是一个有用的模型。

后两节的基础。

第七讲有依赖的背包问题另一种给物品的选取加上限制的方法。

第八讲泛化物品我自己关于背包问题的思考成果,有一点抽象。

背包问题系列(01背包、完全背包、多重背包)

背包问题系列(01背包、完全背包、多重背包)

背包问题系列(01背包、完全背包、多重背包)背包问题是⼀个经典的动态规划问题,问题可以描述为:给定⼀组物品,每种物品都有⾃⼰的重量和价格,在限定的总重量内,我们如何选择,才能使得物品的总价格最⾼。

根据给定物品的数量,背包问题⼜可分为:1)每种物品只有⼀件,即01背包问题2)每种物品不限数量,可选取任意数量,即完全背包问题3)每种物品的数量已给定,不可超出该数量,即多重背包问题背包问题的重点:1)编写状态转移⽅程2)空间优化1 #include <iostream>2 #include <vector>3using namespace std;45int max(int a, int b)6 {7return a > b ? a : b;8 }910int min(int a, int b)11 {12return a < b ? a : b;13 }1415// 01背包问题,n件物品,重量为v16int BagProblem_01(const vector<int> &weight, const vector<int> &value, int n, int v)17 {18// 前i件物品背包限重为j的情况下的最⼤值19 vector<vector<int>> dp(n, vector<int>(v + 1, 0));2021for (int i = 0; i <= v; i++)22 {23if (i >= weight[0])24 {25 dp[0][i] = value[0];26 }27 }2829for (int i = 1; i < n; i++)30 {31for (int j = 1; j <= v; j++)32 {33if (j < weight[i])34 {35 dp[i][j] = dp[i - 1][j];36 }37else38 {39 dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);40 }41 }42 }4344return dp[n - 1][v];45 }4647// 01背包问题--优化空间48int BagProblem_01_optimize(const vector<int> &weight, const vector<int> &value, int n, int v)49 {50// 前i件物品背包限重为j的情况下的最⼤值51 vector<int> dp(v + 1, 0);5253for (int i = 0; i <= v; i++)54 {55if (weight[0] > v)56 {57 dp[0] = value[0];58 }59 }6061for (int i = 1; i < n; i++)62 {63for (int j = v; j >= weight[i]; j--) // dp[j]是由上⼀⾏<=j列推出,j需逆向枚举64 {65 dp[j] = max(dp[j], dp [j - weight[i]] + value[i]);66 }67 }6869return dp[v];70 }7172// 完全背包问题73int BagProblem_complete(const vector<int> &weight, const vector<int> &value, int n, int v)74 {75 vector<vector<int>> dp(n, vector<int>(v + 1, 0));7677for (int j = 0; j <= v; j++)78 {79 dp[0][j] = j / weight[0] * value[0];80 }8182for (int i = 1; i < n; i++)83 {84for (int j = 0; j <= v; j++)85 {86if (j < weight[i])87 {88 dp[i][j] = dp[i - 1][j];89 }90else91 {92 dp[i][j] = max(dp[i - 1][j], dp[i][j - weight[i]] + value[i]);93 }94 }95 }9697return dp[n - 1][v];98 }99100// 完全背包问题——优化空间101int BagProblem_complete_optimize(const vector<int> &weight, const vector<int> &value, int n, int v)102 {103 vector<int> dp(v + 1, 0);104105for (int j = 0; j <= v; j++)106 {107 dp[j] = j / weight[0] * value[0];108 }109110for (int i = 1; i < n; i++)111 {112for (int j = 0; j <= v; j++) // dp[j]是由上⼀⾏j列和本⾏⼩于j列推出,因此需要正向枚举113 {114if (j >= weight[i])115 {116 dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);117 }118 }119 }120121return dp[v];122 }123124// 多重背包问题125int BagProblem_multi(const vector<int> &weight, const vector<int> &value, const vector<int> &nums, int n, int v) 126 {127 vector<vector<int>> dp(n, vector<int>(v + 1, 0));128129for (int j = 0; j <= v; j++)130 {131int num = min(j / weight[0], nums[0]);132 dp[0][j] = num * value[0];133 }134135for (int i = 1; i < n; i++)136 {137for (int j = 0; j <= v; j++)138 {139if (j < weight[i])140 {141 dp[i][j] = dp[i - 1][j];142 }143else144 {145int num = min(j / weight[i], nums[i]);146for (int k = 0; k <= num; k++)147 {148 dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - k * weight[i]] + k * value[i]);149 }150 }151 }152 }153154return dp[n - 1][v];155 }156157// 多重背包问题——优化空间158int BagProblem_multi_optimize(const vector<int> &weight, const vector<int> &value, const vector<int> &nums, int n, int v) 159 {160 vector<int> dp(v + 1, 0);161162for (int j = 0; j <= v; j++)163 {164int num = min(j / weight[0], nums[0]);165 dp[j] = num * value[0];166 }167168for (int i = 1; i < n; i++)169 {170for (int j = v; j >= 0; j--) // dp[j]是由上⼀⾏<=j列推出,需要逆向枚举171 {172int num = min(j / weight[i], nums[i]);173for (int k = 0; k <= num; k++)174 {175if (j < k * weight[i])176continue;177 dp[j] = max(dp[j], dp[j - k * weight[i]] + k * value[i]);178 }179 }180 }181182return dp[v];183 }184185int main()186 {187int v = 10;188int n = 5;189 vector<int> weight{ 2, 2, 4, 6, 3 };190 vector<int> value { 1, 3, 3, 5, 6 };191 vector<int> nums { 1, 2, 3, 4, 1 };192193 cout << BagProblem_01(weight, value, n, v) << endl;194 cout << BagProblem_01_optimize(weight, value, n, v) << endl;195196 cout << BagProblem_complete(weight, value, n, v) << endl;197 cout << BagProblem_complete_optimize(weight, value, n, v) << endl;198199 cout << BagProblem_multi(weight, value, nums, n, v) << endl;200 cout << BagProblem_multi_optimize (weight, value, nums, n, v) << endl;201202return0;203 }。

背包问题----完全背包(最优方案总数分析及实现)

背包问题----完全背包(最优方案总数分析及实现)

背包问题----完全背包(最优⽅案总数分析及实现)本⼈博⽂》中已详细谈过完全背包问题,同时在博⽂》中也总结过01背包的最优⽅案总数的实现。

这⾥我们模仿01背包最优⽅案总数⽅法给出完全背包的最优⽅案求解⽅法。

重写完全背包的动态规划的状态及状态⽅程:完全背包是在N种物品中选取若⼲件(同⼀种物品可多次选取)放在空间为V的背包⾥,每种物品的体积为C1,C2,…,C n,与之相对应的价值为W1,W2,…,W n.求解怎么装物品可使背包⾥物品总价值最⼤。

设物品种类为N,背包容量为V,每种物品的体积为C[i],价值为W[i]。

⼦问题定义:F[i][j]表⽰前i种物品中选取若⼲件物品放⼊剩余空间为j的背包中所能得到的最⼤价值。

状态⽅程为:(2-2)在⽂章》中曾定义G[i][j]代表F[i][j]的⽅案总数。

这⾥我们也做相同的定义,那么最终的结果应该为G[N][V]。

由01背包转变到完全背包后G[i][j]该怎么求?对于01背包来说,G[i][j]求法如下(摘⾃:》):如果F[i][j]=F[i-1][j]且F[i][j]!=F[i-1][j-C[i]]+W[i]说明在状态[i][j]时只有前i-1件物品的放⼊才会使价值最⼤,所以第i件物品不放⼊,那么到状态[i][j]的⽅案数应该等于[i-1][j]状态的⽅案数即G[i][j]=G[i-1][j];如果F[i][j]=F[i-1][j-C[i]]+W[i] 且F[i][j]!=F[i-1][j]说明在状态[i][j]时只有第i件物品的加⼊才会使总价值最⼤,那么⽅案数应该等于[i-1][j-C[i]]的⽅案数,即G[i] [j]=G[i-1][j-C[i]];如果F[i][j]=F[i-1][j-C[i]]+W[i] 且F[i][j]=F[i-1][j]则说明即可以通过状态[i-1][j]在不加⼊第i件物品情况下到达状态[i][j],⼜可以通过状态[i-1][j-C[i]]在加⼊第i件物品的情况下到达状态[i][j],并且这两种情况都使得价值最⼤且这两种情况是互斥的,所以⽅案总数为G[i][j]=G[i-1][j-C[i]]+ G[i-1][j]。

完全背包问题

完全背包问题

完全背包题目:带地重量不超过30 kg,使热量最大数据如下:4 85 116 137 159 22#include <iostream>using namespace std;int f[1001];struct node{int a;int b;};node arry[101];int main(){int n,c;while(cin>>n>>c){for(int i=0;i<c;i++)cin>>arry[i].a>>arry[i].b;memset(f,0,sizeof(f));for(int i=0;i<c;i++)for(int v=arry[i].a;v<=n;v++){if(f[v]>f[v-arry[i].a]+arry[i].b)f[v]=f[v];elsef[v]=f[v-arry[i].a]+arry[i].b;}cout<<f[n]<<endl;/*int sum=0;for(int i=n;i>=0;i--){printf("%d ",f[i]);sum++;if(sum%10==0)printf("\n");}cout << endl<<endl;*/}return 0;}分析:什么叫完全背包了,就是一个物品不一定只取一个,可以取多个,直到取不到为止了!这就是和01背包不同之处;下面我来介绍一下怎么解决这种问题:基本思路这个问题非常类似于01背包问题,所不同的是每种物品有无限件。

也就是从每种物品的角度考虑,与它相关的策略已并非取或不取两种,而是有取0件、取1件、取2件……等很多种。

如果仍然按照解01背包时的思路,令f[i][v]表示前i种物品恰放入一个容量为v的背包的最大权值。

仍然可以按照每种物品不同的策略写出状态转移方程,像这样:f[i][v]=max{f[i-1][v-k*c[i]]+k*w[i]|0<=k*c[i]<=v}这跟01背包问题一样有O(VN)个状态需要求解,但求解每个状态的时间已经不是常数了,求解状态f[i][v]的时间是O(v/c[i]),总的复杂度可以认为是O(V*Σ(V/c[i])),是比较大的。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

第6课竞赛总分(inflate)
【问题描述】
学生在USACO竞赛中得分越多我们越高兴。

我们试着设计竞赛以便学生尽可能多得分。

现在要进行一次竞赛,总时间T固定,有若干类型可选的题目,每种类型题目可选入的数量不限,每种类型题目有一个S1(解答此题所得的分数)和ti(解答此题所需的时间),现要选择若干题目,使解这些题的总时间在T以内的前提下,所得的总分最大。

【输入格式】
第1行:两个整数,竞赛的时间t(1≤t≤10000)和题目类型数n(1≤n≤10000);
第2~n+1行:两个整数,每种类型题目的分数和耗时。

第一个整数说明解决这种题目能得的分数(1≤S1≤10000),第二个整数说明解决这种题目所需的时间(1≤ti≤10000)。

【输出格式】
单独的一行,在给定时间里得到的最大总分。

【输入样例】
3004
10060
250120
120100
3520
【输出样例】
605
样例说明:从第2种类型中选两题和第4种类型中选三题。

分析问题
这个问题非常类似于01背包问题,所不同的是每种物品有无限件。

也就是从每种物品的角度考虑,与它相关的策略已并非取或不取两种,而是有取0件、取1件、取2件……等很多种。

如果仍然按照解01背包时的思路,令f[i,j]表示前i种物品放入容量为j的背包的最大值,可得状态转移方程如下:
f[i,j]=max{f[i-l,j-k×t[i]]+k×s[i]10≤k×t[i]≤T}
这跟01背包问题一样有O(n×T)个状态需要求解,但求解每个状态的时间已经不是常数了,求解状态f[i,j]的时间是O(T/t[i]),总的复杂度约为O(T×n×ave(T/t[i])),ave(T/t [i])表示T/t[i]的平均值。

解决问题
我们将01背包问题一维的实现方法的基本思路加以改进。

首先想想,为什么01背包程序中要按照for j:=T downto t[i]do来循环?这是因为要保证第i次循环中第i件物品只选一次,保证在考虑“选入第i件物品”时,依据的是一个从未选过第i件物品的子结果g[j-t[i]]。

现在完全背包的特点恰是每种物品可选无限件,所以在考虑“加选一件第i种物品”时,正需要一个可能已选入第i种物品的子结果g[j-t[i]],所以就可以采用for j:=t[i]to T do 的顺序循环。

状态转移方程如下:
g j=max{g[j],g[j-t[i]])(1≤i≤n,t[i]≤j≤T)
该算法的时间复杂度为O(n×T)。

参考程序如下:
var g:array[0..10002]of longint;
n,time,i,j:integer;
s,t:array[1..10000]of integer;
begin
readln(time,n);
for i:=1to n do readln(s[i],t[i]);
for i:=1to n do
for j:=t[i]to time do
if g[j]<g[j-t[i]]+s[i]then g[j]:=g[j-t[i]]+s[i];
writeln(g[time]);
end.
活学活用
1.货币系统(money)
【问题描述】
母牛们不但创建了它们自己的政府,而且选择建立了自己的货币系统。

它们对货币的数值感到好奇。

传统地,一个货币系统是由1,5,10,20或25,50,100的单位面值组成的。

母牛想知道用货币系统中的货币来构造一个确定的面值,有多少种不同的方法。

举例来说,使用一个货币系统{1,2,5,10,…}产生18单位面值的一些可能的方法是:18×1,9×2,8×2+2×1,3×5+2+1等等。

写一个程序,计算用给定的货币系统来构造一个确定的面值有多少种方法。

【输入格式】
第1行有两个整数n,v,其中v(1≤v≤25)表示货币系统中货币的种类,n是要构造的面值
(1≤n≤10000);
第2~v+l行:表示可用的货币面值(每行一个)。

【输出格式】
输出方案总数。

【输入样例】
310
1
2
5
【输出样例】
10
2.金银岛(coin)
【问题描述】
在金银岛上,人们使用的货币的值都是完全平方数,例如1,4,9,…,289。

支付十元钱有下列四种方法:
(1)十个一元的钱;
(2)一个四元的,六个一元的;
(3)两个四元的,两个一元的;
(4)一个九元的,一个一元的。

你的任务是对于给定的钱数(设其值少于300),求出支付方法的总数。

【输入格式】
输入共有n+l行(n未知),以数字O结束,每行为一个自然数t(1≤t≤300)。

【输出格式】
输出共有n行,每行表示对于给定的钱数t,对应的支付方案总数。

【输入样例】
2
10
30
【输出样例】
1
4
27
3.质数和分解(resolve)
【问题描述】
任何大于l的自然数n,都可以写成若干个大于等于2且小于等于n的质数之和的形式f (包括只有一个数构成的和表达式的情况),并且可能有不止一种质数和的形式。

例如9的质数和表达式就有四种本质不同的形式:9=2+5+2=2+3+2+2=3+3+3=2+7。

这里所谓两个本质相同的表达式,是指可以通过交换其中一个表达式中参加和运算的各个数的位置而直接得到另一个表达式。

试编程求解自然数n可以写成多少种本质不同的质数和的表达式。

【输入格式】
每一行存放一个自然数n(2≤n≤200)。

【输出格式】
输出自然数n的本质不同的质数和表达式的数目。

【输入输出样例】
输入输出
样例121
样例22009845164。

相关文档
最新文档