NYOJ 还是01背包(枚举+二分)
来源:互联网 发布:淘宝可用微信付款吗 编辑:程序博客网 时间:2024/06/05 03:01
还是01背包
时间限制:10000 ms | 内存限制:228000 KB
难度:5
描述
有n个重量和价值分别为 wi 和 vi 的物品,从这些物品中挑选总重量不超过W的物品,求所有挑选方案中价值总和的最大值。
输入
多组测试数据。
每组测试数据第一行输入n 和 W ,接下来有n行,每行输入两个数,代表第i个物品的wi 和 vi。
1 <= n <=40
1 <= wi <= 10^15
1 <= vi <= 10^15
1 <= W <= 10^15
输出
每组数据输出一行,代表挑选方案中价值总和的最大值。
样例输入
4 5
2 3
1 2
3 4
2 2
样例输出
时间限制:10000 ms | 内存限制:228000 KB
难度:5
描述
有n个重量和价值分别为 wi 和 vi 的物品,从这些物品中挑选总重量不超过W的物品,求所有挑选方案中价值总和的最大值。
输入
多组测试数据。
每组测试数据第一行输入n 和 W ,接下来有n行,每行输入两个数,代表第i个物品的wi 和 vi。
1 <= n <=40
1 <= wi <= 10^15
1 <= vi <= 10^15
1 <= W <= 10^15
输出
每组数据输出一行,代表挑选方案中价值总和的最大值。
样例输入
4 5
2 3
1 2
3 4
2 2
样例输出
7
这题写了好久,调了好久,心塞。
这题解题思路是这样的,首先看一下vi, wi, W便知太大了,所有的背包动态规划方程都显得无能为力了。看一下n<=40, 没办法了只能从这边入手了。怎么做呢?没想到其他的,直接枚举就是了。但是枚举也是需要技巧的,40个得有2^40的量,会崩溃的额,也就是说时间复杂度为O(2^n);接下来就是要做优化工作了。其实以前做题的时候也做过类似思想的题,就是把n个物品分成两半,每一半就剩下n/2个,这样复杂度降的很多。用一个整数来表示方案,用到位运算来表示,例如2的二进制位11,这表示第一个和第二个都拿,又如1的二进制数为01, 这表示第一个拿,第二个物品不拿,这样表示简洁简单且速度快。设前半部分某种方案是得到的重量为w1, 价值为v1,这在第二部分中w2,v2必定有w2+w1<=W; 所以就枚举第一部分,再去第二部分中找w2<=W-w1时价值的最大值。然后第二部分开始时就应该按wi,,vi的字典序排序,因为如果有wi<wj,vi>vj那么i方案一定优于j方案。所以在第二部分中排完序之后会剔除掉某些方案。然后既然排好序就得按二分思想来查找。
AC代码:
# include <cstdio># include <algorithm>using namespace std;typedef long long int ll;struct goods{ll w;ll v;};goods s1[30], s2[30];//输入数据 goods change_s2[(1<<20)+10];//转化为w与v的和 int compare(goods a, goods b){//sort中的比较函数 if(a.w!=b.w){return a.w<b.w;}return a.v<b.v;}int main(){int n, i, v1, v2, cur1, cur2, part1, part2, _cur1, _cur2, left, right, mid;ll sum_w, sum_v, W, num_set, temp, now_w, now_v, w2, ans;while(scanf("%d%lld", &n, &W)!=EOF){part1=n/2;part2=n-part1;for(i=1; i<=part1; i++){scanf("%lld%lld", &s1[i].w, &s1[i].v);}for(i=1; i<=part2; i++){scanf("%lld%lld", &s2[i].w, &s2[i].v);}cur2=1;//枚举第二部分中的所有结果,并存储起来 ,存储的//是每种方案中w和v的和 for(num_set=0; num_set<=(1<<part2)-1; num_set++){ temp=num_set;sum_w=0;sum_v=0;for(i=1; i<=part2; i++){if(temp&1){sum_w=sum_w+s2[i].w;sum_v=sum_v+s2[i].v;}temp=temp>>1;}change_s2[cur2].w=sum_w;change_s2[cur2].v=sum_v;cur2++;}//排序 sort(change_s2+1, change_s2+cur2, compare);now_v=-1;_cur2=1;//剔除掉一些不符合的方案 for(i=1; i<=cur2-1; i++){if(change_s2[i].v>now_v){change_s2[_cur2].v=change_s2[i].v;change_s2[_cur2].w=change_s2[i].w;_cur2++;now_v=change_s2[i].v;}}ans=0;//枚举第一部分的所有情况并到第二部分二分搜索 for(num_set=0; num_set<=(1<<part1)-1; num_set++){sum_w=0;sum_v=0;temp=num_set;for(i=1; i<=part1; i++){if(temp&1){sum_w=sum_w+s1[i].w;sum_v=sum_v+s1[i].v;}temp=temp>>1; }if(sum_w<=W){w2=W-sum_w;left=1;right=_cur2-1;//二分搜索 while(left<=right){mid=(left+right)/2;if(change_s2[mid].w<=w2){left=mid+1;if(ans<sum_v+change_s2[mid].v){ans=sum_v+change_s2[mid].v;}}else{right=mid-1;}}}}printf("%lld\n", ans);}return 0;}
1 0
- NYOJ 还是01背包(枚举+二分)
- NYOJ 题目1091 还是01背包(二分,超大01背包)
- nyoj 1091 还是01背包
- NYOJ 1091 还是01背包
- nyoj--586--疯牛(二分&&枚举)
- 超大背包问题(枚举二分)
- nyoj 疯牛 586 (二分&&枚举) 好题
- NYOJ-586 疯牛 二分枚举+贪心
- NYOJ 586.疯牛(二分枚举+贪心)
- nyoj-289-苹果(01背包)
- NYOJ 1221 找数达人(01背包)
- nyoj 苹果 289 (简单01背包)
- nyoj--289--苹果(01背包)
- nyoj--289--苹果(01背包)
- nyoj 860 (01背包 变形)
- NYOJ-203-三国志(SPFA+01背包)
- nyoj 289 苹果 (01背包)
- NYOJ 289-苹果(01背包)
- my ideas,so chaos..
- HDOJ5672
- SVM学习总结
- 重叠社区发现-LFM算法
- 汇编与驱动-采用SSDT Hook NtOpenProcess保护进程
- NYOJ 还是01背包(枚举+二分)
- hdoj2602 01背包
- HDUOJ1864最大报销额(01背包)
- hrbust/哈理工oj 1526 小猴和冒泡【归并排序】
- iOS学习笔记48-Swift(八)反射
- MySQL存储引擎
- hdoj2036多边形面积的求法
- 第十一周项目3.1 警察和厨师
- Android开发本地及网络Mp3音乐播放器(十二)创建NetMusicListAdapter、SearchResult显示网络音乐列表