nyist oj 311 全然背包 (动态规划经典题)

全然背包

时间限制:3000 ms  |  内存限制:65535 KB

难度:4

描写叙述

直接说题意,全然背包定义有N种物品和一个容量为V的背包。每种物品都有无限件可用。第i种物品的体积是c,价值是w。

求解将哪些物品装入背包可使这些物品的体积总和不超过背包容量,且价值总和最大。本题要求是背包恰好装满背包时,求出最大价值总和是多少。

假设不能恰好装满背包,输出NO

输入
第一行: N 表示有多少组測试数据(N<7)。

接下来每组測试数据的第一行有两个整数M。V。 M表示物品种类的数目,V表示背包的总容量。(0<M<=2000,0<V<=50000)

接下来的M行每行有两个整数c,w分别表示每种物品的重量和价值(0<c<100000,0<w<100000)

输出
相应每组測试数据输出结果(假设能恰好装满背包,输出装满背包时背包内物品的最大价值总和。

假设不能恰好装满背包,输出NO)

例子输入
2
1 5
2 2
2 5
2 2
5 1
例子输出
NO
1
上传者

userid=ACM_%E8%B5%B5%E9%93%AD%E6%B5%A9" style="text-decoration:none; color:rgb(55,119,188)">ACM_赵铭浩

动态规划经典题;也有几种思路,最优的思路把01背包问题的第二重循环的顺序改一下,就得到了全然背包的最优解法;

这个算法使用一维数组,先看伪代码:(引用的背包9讲里面的内容)

for i=1..N
    for v=0..V
        f[v]=max{f[v],f[v-cost]+weight}

你会发现,这个伪代码与01背包的伪代码仅仅有v的循环次序不同而已。 为什么这样一改就可行呢?首先想想为什么P01中要依照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][v-c[i]],所以就能够而且必须採用v=0..V的顺序循环。这就是这个简单的程序为何成立的道理。

值得一提的是,上面的伪代码中两层for循环的次序能够颠倒。这个结论有可能会带来算法时间常数上的优化。

这个算法也能够以另外的思路得出。

比如。将基本思路中求解f[i][v-c[i]]的状态转移方程显式地写出来,代入原方程中,会发现该方程能够等价地变形成这样的形式:

f[i][v]=max{f[i-1][v],f[i][v-c[i]]+w[i]}

将这个方程用一维数组实现,便得到了上面的伪代码。

以下是实现的代码;动态规划的代码都非常easy,最重要的是掌握当中的状态转移方程:

#include <cstdio>
#include <cstring>
#define max(a,b) a>b?

a:b
const int maxn=50001;
int dp[maxn];
int main()
{
    int n,m,v,i,j,c,w;
    scanf("%d",&n);
    while(n--)
    {
      memset(dp,-10000,sizeof(dp));//这里也要注意,在01背包中初始化给的是0,这里要初始化一个比較大的负数
      dp[0]=0;//这里也要注意,没有这个就会wa
      scanf("%d%d",&m,&v);
      for(i=1;i<=m;i++)
      {
          scanf("%d%d",&c,&w);
          for(j=c;j<=v;j++)
                dp[j]=max(dp[j],dp[j-c]+w);//状态转移方程也和01背包一致
      }
      if(dp[v]<0) printf("NO\n");
       else  printf("%d\n",dp[v]);
    }
    return 0;
}
时间: 2024-10-26 00:43:08

nyist oj 311 全然背包 (动态规划经典题)的相关文章

nyist oj 311 完全背包 (动态规划经典题)

完全背包 时间限制:3000 ms  |  内存限制:65535 KB 难度:4 描述 直接说题意,完全背包定义有N种物品和一个容量为V的背包,每种物品都有无限件可用.第i种物品的体积是c,价值是w.求解将哪些物品装入背包可使这些物品的体积总和不超过背包容量,且价值总和最大.本题要求是背包恰好装满背包时,求出最大价值总和是多少.如果不能恰好装满背包,输出NO 输入 第一行: N 表示有多少组测试数据(N<7). 接下来每组测试数据的第一行有两个整数M,V. M表示物品种类的数目,V表示背包的总容

nyist oj 79 拦截导弹 (动态规划基础题)

拦截导弹 时间限制:3000 ms  |  内存限制:65535 KB 难度:3 描述 某国为了防御敌国的导弹袭击,发展中一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于等于前一发的高度.某天,雷达捕捉到敌国导弹来袭.由于该系统还在试用阶段,所以只用一套系统,因此有可能不能拦截所有的导弹. 输入 第一行输入测试数据组数N(1<=N<=10) 接下来一行输入这组测试数据共有多少个导弹m(1<=m<=20) 接下来行输

nyist oj 17 单调递增最长子序列 (动态规划经典题)

单调递增最长子序列 时间限制:3000 ms  |  内存限制:65535 KB 难度:4 描述 求一个字符串的最长递增子序列的长度 如:dabdbf最长递增子序列就是abdf,长度为4 输入 第一行一个整数0<n<20,表示有n个字符串要处理 随后的n行,每行有一个字符串,该字符串的长度不会超过10000 输出 输出字符串的最长递增子序列的长度 样例输入 3 aaa ababc abklmncdefg 样例输出 1 3 7 来源 经典题目 动态规划的经典题目:好像还有好几种解法,我现在研究的

HDU 1114 Piggy-Bank 全然背包

Piggy-Bank Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Description Before ACM can do anything, a budget must be prepared and the necessary financial support obtained. The main income for this action come

nyist oj 36 最长公共子序列 (动态规划基础题)

最长公共子序列 时间限制:3000 ms  |  内存限制:65535 KB 难度:3 描述 咱们就不拐弯抹角了,如题,需要你做的就是写一个程序,得出最长公共子序列. tip:最长公共子序列也称作最长公共子串(不要求连续),英文缩写为LCS(Longest Common Subsequence).其定义是,一个序列 S ,如果分别是两个或多个已知序列的子序列,且是所有符合此条件序列中最长的,则 S 称为已知序列的最长公共子序列. 输入 第一行给出一个整数N(0<N<100)表示待测数据组数 接

nyist oj 37 回文字符串 (动态规划经典)

回文字符串 时间限制:3000 ms  |  内存限制:65535 KB 难度:4 描述 所谓回文字符串,就是一个字符串,从左到右读和从右到左读是完全一样的,比如"aba".当然,我们给你的问题不会再简单到判断一个字符串是不是回文字符串.现在要求你,给你一个字符串,可在任意位置添加字符,最少再添加几个字符,可以使这个字符串成为回文字符串. 输入 第一行给出整数N(0<N<100) 接下来的N行,每行一个字符串,每个字符串长度不超过1000. 输出 每行输出所需添加的最少字符

nyist oj 214 单调递增子序列(二) (动态规划经典)

单调递增子序列(二) 时间限制:1000 ms  |  内存限制:65535 KB 难度:4 描述 给定一整型数列{a1,a2...,an}(0<n<=100000),找出单调递增最长子序列,并求出其长度. 如:1 9 10 5 11 2 13的最长单调递增子序列是1 9 10 11 13,长度为5. 输入 有多组测试数据(<=7) 每组测试数据的第一行是一个整数n表示序列中共有n个整数,随后的下一行里有n个整数,表示数列中的所有元素.每个整形数中间用空格间隔开(0<n<=1

nyist oj 289 苹果 (动态规划——背包问题)

苹果 时间限制:3000 ms  |  内存限制:65535 KB 难度:3 描述 ctest有n个苹果,要将它放入容量为v的背包.给出第i个苹果的大小和价钱,求出能放入背包的苹果的总价钱最大值. 输入 有多组测试数据,每组测试数据第一行为2个正整数,分别代表苹果的个数n和背包的容量v,n.v同时为0时结束测试,此时不输出.接下来的n行,每行2个正整数,用空格隔开,分别代表苹果的大小c和价钱w.所有输入数字的范围大于等于0,小于等于1000. 输出 对每组测试数据输出一个整数,代表能放入背包的苹

nyist oj 448 寻找最大数 (基础题)

寻找最大数 时间限制:1000 ms  |  内存限制:65535 KB 难度:2 描述 请在整数 n 中删除m个数字, 使得余下的数字按原次序组成的新数最大, 比如当n=92081346718538,m=10时,则新的最大数是9888 输入 第一行输入一个正整数T,表示有T组测试数据 每组测试数据占一行,每行有两个数n,m(n可能是一个很大的整数,但其位数不超过100位,并且保证数据首位非0,m小于整数n的位数) 输出 每组测试数据的输出占一行,输出剩余的数字按原次序组成的最大新数 样例输入