HDU 2191 悼念汶川地震(多重背包)
思路:
多重背包转成01背包,怎么转?把一种大米看成一堆单个的物品,每件物品要么装入,要么不装。复杂度比01背包要大。时间复杂度为O(vns)(这里S是所有物品的数量s之和)。这个做法太粗糙了,但就是AC了。假如某一种大米有很多件,那麻烦大了。
0MS 1084K 706B C++
这是用“单纯转01背包”实现的,速度还这么快,还需优化不?
# include <stdio.h>
# include <string.h>
int dp[] ;//转成01背包的解法,没有任何优化。
int max(int a,int b)
{
return a>b?a:b;
}
int main ()
{
int T, ans, n, m ;
int p, h, c, i, j ;
scanf ("%d", &T) ;
while (T--)
{
scanf ("%d%d", &n, &m) ; //n是经费,m是种类
memset (dp, , sizeof(dp)) ;
ans = ;
while (m--)
{
scanf ("%d%d%d", &p, &h, &c) ;
for(i = ; i<=c ; i++) //m是经费
{
for(j = n ; j >= p ;j--)
{
dp[j]=max(dp[j],dp[j-p]+h);
}
}
}
printf ("%d\n", dp[n]) ;
}
return ;
}
2191
未实现的想法:按照完全背包的做法,在里面加一些东西来控制“数量不够”的情况。当数量已达上限,用做大数量来代替,那么需要比较的两个dp值就是dp[j]与dp[j-1],分别代表不装、装满。另用一个数组来记录每个不同的经费上限对应dp数组中所用的第i种大米的数量。这个数组要在不同i时更新为0,有开销。这个想法实现不了。
#include <iostream>
#define limit 110
using namespace std;
int p[limit]; //单价
int h[limit]; //净重
int c[limit]; //数量上限
int u[limit]; //已买的数量
int dp[limit];
int max(int a,int b)
{
return a>b?a:b;
}
void cal(int n,int m)
{
int temp=,j,i;
for(i=;i<m;i++)
{
for(j=;j<=n;j++) //初始化数组u
u[j]=;
for( j=p[i];j<=n;j++)
{
temp=max( dp[j],dp[j-p[i]]+h[i] );
if(temp==dp[j-p[i]]+h[i]) //需要加多一件
{
if(u[j-p[i]]<c[i]) //第i件还有剩余,可以买。
{
u[j]=u[j-p[i]]+;
dp[j]=temp;
}
else //被用光了,但是为了防止前大于后的情况,在不能追加的情况下,仍需比较前后的大小,保证后总大于前
{
dp[j]=max(dp[j-],dp[j]); //仅需比较1个,因前面每个所使用的并不是升序的,可能无序的
if(dp[j]==dp[j-])
u[j]=u[j-];//因为u[j]本来就是0,所以else的情况不用赋零
}
}
}
}
return;
}
void main()
{
int q,n,m,i;
scanf("%d",&q);
while(q--)
{
memset(dp,,sizeof(dp));
scanf("%d%d",&n,&m); //经费的金额 大米的种类
for(i=;i<m;i++)
{
scanf("%d%d%d",&p[i],&h[i],&c[i]); //分别表示每袋的价格、每袋的重量以及对应种类大米的袋数
}
cal(n,m);
printf("%d\n",dp[n]);
}
}
2191
可行的思路①:01背包+二进制法。 二进制的真谛啊。
#include <iostream>
#include <algorithm>
#define limit 110
using namespace std;
int p[limit]; //单价
int h[limit]; //净重
int c[limit]; //数量上限
int dp[limit]; int max(int a,int b)
{
return a>b?a:b;
}
void cal(int n,int m)
{
int temp=,j,i,k,nCount;
for(i=;i<m;i++)
{
k = ;
nCount = c[i];
while(k <= nCount)
{
for( j=n;j>=k*p[i];j--)
{
dp[j] = max(dp[j],dp[j - k*p[i]] + k*h[i]);
}
nCount -= k;
k <<= ; // <<就是左移
}
if(nCount!=) // 不是刚好2的几次方,另外处理
for( j=n; j>=nCount*p[i] ;j-- )
{
dp[j] = max( dp[j] , dp[j - nCount*p[i]] + nCount*h[i] );
}
}
}
void main()
{
int q,n,m,i;
scanf("%d",&q);
while(q--)
{
memset(dp,,sizeof(dp));
scanf("%d%d",&n,&m); //经费的金额 大米的种类
for(i=;i<m;i++)
{
scanf("%d%d%d",&p[i],&h[i],&c[i]); //分别表示每袋的价格、每袋的重量以及对应种类大米的袋数
}
cal(n,m);
printf("%d\n",dp[n]);
}
}
2191
讲一下用01背包+二进制法:将每种大米的件数分成1,2,4,8,16,32....这么多份,即1+2+4+8+....=第i种大米的件数。 在分的时候最后一件不一定刚好是2的几次方形式,是多少就是多少,待单独处理。那么假如13就分成了1,2,4,6了,这里的6就是不足2^3=8才是6的。在单纯转01背包的方式中,每种大米的每一件都单独处理,而二进制法是将分好的几件归为一件对待。比如第一种大米是13件,在单纯转01背包时,最里层是需要13次循环的,但是在二进制法的01背包中,它被分成1,2,4,6件共4堆,我们把每堆当成一件,捆绑在一起的,在更新dp数组的时候按大小的顺序来循环,即第1次循环是1件,第2次循环是2件套装,第3次循环是4件套,第4次循环是6件套。这里的最里层循环就变成了4次循环了。减少的计算量是很客观的。
15MS 1096K 1030B c++
可行的思路②:在转成01背包上作优化。完全背包+01背包来解,即:某一种大米的数量*单价>=经费,那么就是完全背包型;否则就是01背包型。但如果遇到都是01背包型,此优化没用了。
#include <iostream>
#include <algorithm>
#define limit 110
using namespace std;
int p[limit]; //单价
int h[limit]; //净重
int c[limit]; //数量上限
int dp[limit];
int n,m;
int max(int a,int b)
{
return a>b?a:b;
}
void _01pack(int n_p,int n_h) //01背包
{
for (int j = n;j >= n_p;j--)
{
dp[j] = max(dp[j],dp[j - n_p] + n_h);
}
}
void cpack(int n_p,int n_h) //完全背包
{
for (int j = n_p;j <= n;j++)
{
dp[j] = max(dp[j],dp[j - n_p] + n_h);
}
} void cal()
{
int i,k,nCount;
for(i=;i<m;i++)
{
if (p[i] * c[i] >= n)
cpack(p[i],h[i]);
else
{
k = ;
nCount = c[i];
while(k <= nCount)
{
_01pack(k * p[i],k * h[i]);
nCount -= k;
k *= ;
}
_01pack(nCount * p[i],nCount * h[i]);
}
}
}
void main()
{
int q,i;
scanf("%d",&q);
while(q--)
{
memset(dp,,sizeof(dp));
scanf("%d%d",&n,&m); //经费的金额 大米的种类
for(i=;i<m;i++)
{
scanf("%d%d%d",&p[i],&h[i],&c[i]); //分别表示每袋的价格、每袋的重量以及对应种类大米的袋数
}
cal();
printf("%d\n",dp[n]);
}
}
2191
15MS 1096K 1181B c++
其他可行的思路:队列法。复杂度为O(vn),还没理解。所以没代码。
HDU 2191 悼念汶川地震(多重背包)的更多相关文章
- 解题报告:hdu2191汶川地震 - 多重背包模板
2017-09-03 17:01:36 writer:pprp 这是一道多重背包裸题 - 记得是从右向左进行,还有几点需要注意啊,都在代码中表示出来了 代码如下: /* @theme:hdu2191 ...
- HDU 2191 - 单调队列优化多重背包
题目: 传送门呀传送门~ Problem Description 急!灾区的食物依然短缺! 为了挽救灾区同胞的生命,心系灾区同胞的你准备自己采购一些粮食支援灾区,现在假设你一共有资金n元,而市场有m种 ...
- HDOJ(HDU).2191. 悼念512汶川大地震遇难同胞――珍惜现在,感恩生活 (DP 多重背包+二进制优化)
HDOJ(HDU).2191. 悼念512汶川大地震遇难同胞――珍惜现在,感恩生活 (DP 多重背包+二进制优化) 题意分析 首先C表示测试数据的组数,然后给出经费的金额和大米的种类.接着是每袋大米的 ...
- HDU 2191悼念512汶川大地震遇难同胞——珍惜如今,感恩生活(多重背包)
HDU 2191悼念512汶川大地震遇难同胞--珍惜如今.感恩生活(多重背包) http://acm.hdu.edu.cn/showproblem.php?pid=2191 题意: 如果你有资金n元, ...
- HDU 3732 Ahui Writes Word(多重背包)
HDU 3732 Ahui Writes Word(多重背包) http://acm.hdu.edu.cn/showproblem.php? pid=3732 题意: 初始有N个物品, 每一个物品有c ...
- hdu 2191 悼念512汶川大地震遇难同胞 【多重背包】(模板题)
题目链接:https://vjudge.net/problem/HDU-2191 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活 ...
- HDU——2191悼念512汶川大地震遇难同胞(多重背包转化为01背包或二进制优化)
悼念512汶川大地震遇难同胞——珍惜现在,感恩生活 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Jav ...
- --hdu 2191 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活(多重背包)
解题思路: 多重背包:第 i 件物品有 j 个可用. 本题中 第 p[i] 类大米 有 c[i] 袋大米可买 ,故本题为多重背包. n(总钱数).m(种类) p[i] 单价 h[i] 重量 c[i] ...
- 多重背包之 HDU -1171Big Event in HDU &HDU -2191悼念512汶川大地震遇难同胞——珍惜现在,感恩生活
这两道题都是多重背包的基础题,前面的安格题意是:给出每个物体的价值和物体的数量,如何分使得A,B所得价值最接近并且A的价值不能小于B,就类似于NYOJ上的那个邮票分你一半那个意思,只不过这里不是一个而 ...
随机推荐
- 【java数据类型和mysqk数据类型对照表】
java mysql 数据类型对照 类型名称 显示长度 数据库类型 JAVA类型 JDBC类型索引(int) 描述 VARCHAR L+N VARCHAR java.lan ...
- Note: ENDBOX: Scalable Middlebox Functions Using Client-Side Trusted Execution
ENDBOX enable secure networking by client-Side trusted execution. What ENDBOX is a scalable middlebo ...
- 痞子衡嵌入式:恩智浦i.MX RTxxx系列MCU特性介绍(2)- RT685EVKA性能实测(Dhrystone)
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是恩智浦i.MX RTxxx系列MCU的性能. 在前面的文章 i.MXRTxxx微控制器概览 里,痞子衡给大家简介过恩智浦半导体在2018 ...
- [Emacs] Emacs使用介绍
详细,可参考该文档(转载):Emacs 快速指南 - 原生中文手册 C-x C-c 关闭Emacs会话 C-v/M-v 向前/后翻页 C-n/C-p 光标向下/上移一行 C-f/C-b 光标向前/后移 ...
- Codeforces - 102222H - Fight Against Monsters - 贪心
https://codeforc.es/gym/102222/problem/H 题意:有一堆怪兽,怪兽有HP和ATK.你有一个英雄,英雄每次先被所有怪兽打,然后打其中一个怪兽.打的伤害递增,第一次1 ...
- 网格概念 Gutter
Bootstrap4也是由以上基础概念作为发展 Bootstrap 栅栏式排版 , 总栏数为12 (以下代码探寻问题, 实际上使用方法是错误的) <style> .box { heigh ...
- 洛谷P3396 哈希冲突(分块)
传送门 题解在此,讲的蛮清楚的->这里 我就贴个代码 //minamoto #include<iostream> #include<cstdio> #include< ...
- ios一个自定义的下拉多选菜单
前段时间项目刚好要做到条件筛选菜单,正好找到一些别人写的,结合自己实际需求进行优化修改,一个实用的多条件筛选菜单,根据其他的下拉进行一些改进. 点击后返回点击文字显示 github地址:https:/ ...
- 小K的农场 差分约束
题目描述 小K在MC里面建立很多很多的农场,总共n个,以至于他自己都忘记了每个农场中种植作物的具体数量了,他只记得一些含糊的信息(共m个),以下列三种形式描述: 农场a比农场b至少多种植了c个单位的作 ...
- 洛谷P2486 [SDOI2011]染色
题目描述 输入输出格式 输入格式: 输出格式: 对于每个询问操作,输出一行答案. 输入输出样例 输入样例#1: 6 5 2 2 1 2 1 1 1 2 1 3 2 4 2 5 2 6 Q 3 5 C ...