hdu 2126 Buy the souvenirs 【输出方案数】【01背包】(经典)
题目链接:https://vjudge.net/contest/103424#problem/K
转载于:https://blog.csdn.net/acm_davidcn/article/details/5549933
题目大意:
给n个物品,和m块钱,输出能够购买最多物品的个数和购买这么多物品的方案数。
解题分析:
背包的一种进化版 , 除了记录最多能买多少个 , 需要记录买这么多个的方法 , 所以要在二维的基础上加多一维 .
状态转移方程如下 : f[i][j][k]=f[i-1][j-t[i]][k-1]+f[i-1][j][k];
( 前 i 个物品在有 j 元的时候买 k 个物品的方法 ,t[i] 为第 i 个物品的价格 )
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
int val[], dp[][][]; //dp[i][j][k]表示有k块钱,在前i种物品买j个物品的数量
int main() {
int i, j, k, t, n, m, sign;
scanf("%d", &t);
while (t--) {
scanf("%d%d", &n, &m);
for (i = ; i <= n; i++)
scanf("%d", &val[i]);
memset(dp, , sizeof(dp));
for (i = ; i <= n; i++)
for (k = ; k <= m; k++)
dp[i][][k] = ; //初始化,一样不买种类是1
for (i = ; i <= n; i++) {
for (j = ; j <= i; j++)
for (k = m; k >= ; k--) {
if (k >= val[i])
dp[i][j][k] += dp[i - ][j - ][k - val[i]] + dp[i - ][j][k]; //加上买和不买的情况
}
}
sign = ;
for (i = n; i >= ; i--) {
if (dp[n][i][m] != ) { //找购买方案数不为0的最大购买数量i
printf("You have %d selection(s) to buy with %d kind(s) of souvenirs.\n", dp[n][i][m], i);
sign = ;
break;
}
}
if (!sign)
puts("Sorry, you can't buy anything.");
}
return ;
}
第二种方法,对上述代码进行优化
dp[i][j][0]表示前i个物品有j元时的最多物品数,dp[i][j][1]用来储存方案数
***设当前所选的物品为i
1. 若选了物品i后,能买的件数比不选物品i的件数大,即dp[j - val[i]]>dp[j]
那么更新dp[j],同时,dp[j][1]的方案数即为dp[j - val[i]][1]
原因是:假设dp[j - val[i]]的方案数为 AB AC 两种,那么在此情况下加个D,为ABD, ACD,仍为两种,所以dp[j] = f[j - val[i]]即可
当然,要注意dp[j - val[i]]为0的情况,因此当它为0时,dp[j] = 1,1即为D
2. 若选了物品i后,能买的件数比不选物品i的件数相同,即dp[j - val[i]] == dp[j]
即原先不选第i个物品,所需要的方案数为dp[j];而选了物品i的方案数为dp[j - val[i]]。
因此,总的方案数即为dp[j] + dp[j - val[i]]
当然,这里也要注意dp[j - val[i]] = 0的情况,当它为0时,dp[j] += 1,1即为D
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mem(p,k) memset(p,k,sizeof(p))
using namespace std;
int p[], dp[][]; //dp[i][j][0]表示前i个物品,最多有j元,能买多少种物品
int main() { //dp[i][j][1]表示前i个物品,最多有j元,能买最多物品的方案数
int t, cur = ;
cin >> t;
while (t--) {
int m, n;
scanf("%d%d", &n, &m);
for (int i = ; i <= n; i++)scanf("%d", p + i);
mem(dp, );
for (int i = ; i <= m; i++)dp[i][] = ; //初始化,钱数为j,一个物品都不买的方案数为1(因为此时对应的dp[i][0]=0,表示一个物品都没买)
for (int i = ; i <= n; i++) {
for (int j = m; j >= p[i]; j--) {
if (dp[j][] == dp[j - p[i]][] + ) { //若选了物品i后,能买的件数比不选物品i的件数相同
if (!dp[j - p[i]][])dp[j][] += ;
else
dp[j][] += dp[j - p[i]][];
}
else if(dp[j][]<dp[j - p[i]][] + ) { //若选了物品i后,能买的件数比不选物品i的件数大
dp[j][] = dp[j - p[i]][] + ;
if (!dp[j - p[i]][])dp[j][] = ;
else
dp[j][] = dp[j - p[i]][];
}
}
}
if (dp[m][]) {
printf("You have %d selection(s) to buy with %d kind(s) of souvenirs.\n", dp[m][], dp[m][]);
}
else printf("Sorry, you can't buy anything.\n");
}
}
2018-05-21
hdu 2126 Buy the souvenirs 【输出方案数】【01背包】(经典)的更多相关文章
- hdu 2126 Buy the souvenirs 二维01背包方案总数
Buy the souvenirs Time Limit: 10000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Other ...
- HDU 2126 Buy the souvenirs (01背包,输出方案数)
题意:给出t组数据 每组数据给出n和m,n代表商品个数,m代表你所拥有的钱,然后给出n个商品的价值 问你所能买到的最大件数,和对应的方案数.思路: 如果将物品的价格看做容量,将它的件数1看做价值的话, ...
- hdu 2126 Buy the souvenirs(记录总方案数的01背包)
Buy the souvenirs Time Limit: 10000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Other ...
- hdu 2126 Buy the souvenirs 买纪念品(01背包,略变形)
题意: 给出一些纪念品的价格,先算出手上的钱最多能买多少种东西k,然后求手上的钱能买k种东西的方案数.也就是你想要买最多种东西,而最多种又有多少种组合可选择. 思路: 01背包.显然要先算出手上的钱m ...
- [HDU 2126] Buy the souvenirs (动态规划)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2126 题意:给你n个物品,m元钱,问你最多能买个多少物品,并且有多少种解决方案. 一开始想到的是,先解 ...
- hdu 3339 In Action(迪杰斯特拉+01背包)
In Action Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total S ...
- HDU 1203 I NEED A OFFER!(01 背包DP)
点我看题目 题意 : 中文题不详述. 思路 :类似于01背包的DP,就是放与不放的问题,不过这个要求概率,至少得到一份offer的反面就是一份也得不到,所以先求一份也得不到的概率,用1减掉就可以得到所 ...
- HDU 2639 骨头收集者 II【01背包 】+【第K优决策】
题目链接:https://vjudge.net/contest/103424#problem/H 题目大意:与01背包模板题类似,只不过要我们求第K个最大的总价值. 解题分析: 其基本思想是将每个状态 ...
- HDU 5887 Herbs Gathering(搜索求01背包)
http://acm.hdu.edu.cn/showproblem.php?pid=5887 题意: 容量很大的01背包. 思路: 因为这道题目背包容量比较大,所以用dp是行不通的.所以得用搜索来做, ...
随机推荐
- html 替换元素
参考博客:http://www.cnblogs.com/wkylin/archive/2011/05/12/2044328.html 可替换元素也是行内元素 替换元素是浏览器根据其标签的元素与属性来判 ...
- String split方法与Guava Splitter用法区别
String split方法与Guava Splitter用法区别 今天同事写了一段使用String split方法的代码,如下所示,同事期望得到的是字符"1",但是没想到却得到空 ...
- mysql 案例~mysql主从复制延迟处理(2)
一 简介:今天来聊聊周期性从库延迟的问题,是上一篇的基础分析的一个场景 二 背景:近期每天的指定时间段,收到从库延迟的报警,然后过一段时间恢复.由于从库是提供读服务的,所以需要解决 三 分析思路: 1 ...
- MySQL— 进阶
目录 一.视图 二.触发器 三.函数 四.存储过程 五.事务 一.视图 视图是一个虚拟表(非真实存在),其本质是[根据SQL语句获取动态的数据集,并为其命名],用户使用时只需使用[名称]即可获取结果集 ...
- 关注网页的更新状况,了解最新的handsup 消息.
// 第一部分是网页截图和源码保存 // upon page load. var fs = require("fs"); var resourceWait = 300, maxRe ...
- nodejs package.json解释
{ "name": "node-echo", # 包名,在NPM服务器上须要保持唯一 "version": "1.0.0" ...
- Redis简介+常用命令
Redis=REmote DIctionary Server Redis是一个使用C语言编写的开源数据库,是高性能的key-value数据库,是内存数据库,支持数据持久化. Redis常用数据类型: ...
- Json对象和字符串互相转换 数据拼接 JSON使用方式
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式. 一.JSON字符串转换为JSON对象: eval() 和 JSON.parse eg- json字符串: ...
- 解决Myeclipse启动Spring Boot项目报出莫名异常
有时候明明代码.配置都是正确的,但是一启动却报出莫名其妙的异常. 主要原因是resource包下的xml.yml文件或者其他配置文件路径不正确,解决方法如下: 第一步. 第二步.如果Excluded不 ...
- iframe传递参数问题
在页面中嵌入了iframe,如果需要传递参数到iframe中 1.通过将参数嵌入到url中,在iframe中使用${param.xxx}可以获取 2.通过将参数存入到session中,在iframe中 ...