题目链接: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

最新文章

  1. ADO.net 连接字符串中的 |DataDirectory| 是什么
  2. linux安装配置apk打包程序gradle+jdk+Android_sdk+python自动化编译脚本
  3. Struts2框架之-注解开发
  4. WPF之全局快捷键
  5. poj1966 求顶点连通度
  6. |原创|unity 4.3 2D功能SpriteRenderer修改颜色的方法
  7. 深入理解C#泛型
  8. 【BZOJ 1901】【Zju 2112】 Dynamic Rankings 动态K值 树状数组套主席树模板题
  9. 关于MongoDb Replica Set的故障转移集群——理论篇
  10. django入门教程(下)
  11. hdu 1281棋盘游戏(二分匹配)
  12. IO-序列化 Serializable Parcelable Object
  13. Android-1
  14. 常用几个UITableView,UICollectionView &#160;UIScrollView关键点
  15. mysql5.7在windows下面的主从复制配置
  16. EasyUI DataGrid - 嵌套的DataGrid
  17. ●SPOJ 1811 Longest Common Substring
  18. linux 基础命令,未完待续
  19. Javascript强制转换
  20. 关于ASP.NET MVC4在IIS6中不认识安卓移动设备的解决办法

热门文章

  1. UVA - 10480 Sabotage【最小割最大流定理】
  2. python - 系统交互操作(subprocess)
  3. 【转】Python数据类型之“集合(Sets)与映射(Mapping)”
  4. 存储器结构、cache、DMA架构分析--【原创】
  5. Mysql Binlog三种格式介绍及分析【转】
  6. vue学习生命周期(created和mounted区别)
  7. HTML学习笔记06-连接
  8. DOS命令大全(转)
  9. Go语言规格说明书 之 内建函数(Built-in functions)
  10. Day6------------磁盘用满的两种情况