这道题乍一看是普通的01背包,最最基础的,但是仔细一看数据,发现普通的根本没法做,仔细观察数组发现n比较小,利用这个特点将它划分为前半部分和后半部分这样就好了,当时在网上找题解,找不到,后来在挑战程序设计上找到了这个题,就拿来引用一下

挑选物品的方法总从2^n中,直接枚举肯定不行,因为n最大为40,但是如果n为20就可以了,这时候就要用到折半枚举,先枚举前一半,在枚举后一半。先把前把部分的选取方法对应的重量和价值总和记为w1, v1,这样后半部分寻找w2 <= W - w1时 使v2最大的选取方法就好了。

因此,我们要思考从枚举得到的(w2, v2)的集合中高效寻找max{v2|w2<=W'}的方法。首先,显然我们可以排除所有w2[i] <= w2[j]并且v2[i] >= v2[j] 的 j。 这一点可以按照w2,v2的字典序排列后做到。此后剩余的元素都满足w2[i] < w2[j] , v2[i] < v2[j], 要计算max{v2|w2<=W'}的话,只要寻找满足w2[i]<=W'的最大的i就可以了。这可以利用二分搜索完成。剩余的元素个数为M的话,一次搜索要用log(M)的时间,可以解决

代码如下:

方法一(折半枚举):

 #include <iostream>
#include <algorithm>
#include <cstdio>
#define Max(a,b) a>b?a:b
#define INF 10000000000000000
using namespace std;
typedef long long LL;
const int MAX = ;
LL weight[MAX], value[MAX];
LL W;
pair<LL, LL> ps[ << (MAX / )];
int n;
void slove()
{
//枚举前半部分
int n2 = n / ;
for (int i = ; i < << n2; i++)//前半部分的枚举总数为 2^(n/2);
{
LL sw = , sv = ;
//每种结果选取特定的价值和重量(i.e 一共2个东西,就一共四种情况,都不选,选第一个,选第二个,都选)
for (int j = ; j < n2; j++)
{
if (i >> j & )
{
sw += weight[j];
sv += value[j];
}
}
ps[i] = make_pair(sw, sv);//加入到ps数组中
}
//对ps排序
sort(ps, ps + ( << n2));
//ps 去重
int m = ;
for (int i = ; i < << n2; i++)
if (ps[m - ].second < ps[i].second)
ps[m++] = ps[i];
LL res = ;//保存结果
//枚举后半部分, 并且找到最优解
for (int i = ; i < << (n - n2); i++)//同样枚举的总个数
{
LL sw = , sv = ;
for (int j = ; j < n - n2; j++)//和前半部分的一样
{
if (i >> j & )
{
sw += weight[n2 + j];
sv += value[n2 + j];
}
}
if (sw <= W)//加个判断求解最大价值,只有小于背包容量的时候
{
LL tv = (lower_bound(ps, ps + m, make_pair(W - sw, INF)) - )->second;//找到前半部分对应的value
res = Max(res, sv + tv);
}
}
printf("%lld\n", res);
} int main()
{
while (~scanf("%d %lld", &n, &W))
{
for (int i = ; i < n; i++)
scanf("%lld %lld", &weight[i], &value[i]);
slove();
}
return ;
}

这个题也可以用搜做来做,搜索反而来的更快,因为n比较小

方法二(搜索):

 #include <stdio.h>
#include <string.h>
#define Max(a, b) a > b ? a : b
const int MAX = ;
long long weight[MAX], value[MAX], sw[MAX], sv[MAX];
long long W, n, ans;
//i表示当前取到第n-i个,cnt 表示当前的总value, w当前背包剩余的空间
void dfs(int i, long long cnt, long long w)
{
if (i == )//取到最后
{
ans = Max(ans, cnt);
return;
}
if (w == || cnt + sv[i] < ans)//背包满或者当前总的加上这个前i个的总价值小于当前的总value,这步是剪枝
return ;
if (w >= sw[i])//因为是从上往下找的,所以只要当前容量能装下前i个的和,所以这时一定是最大的
{
cnt += sv[i];
ans = Max(ans, cnt);
w = ;
return ;
}
if (w > weight[i])//深搜两种状态
dfs(i - , cnt + value[i], w - weight[i]);//相当于01背包中的两种状态
dfs(i - , cnt, w);
}
int main()
{
while (~scanf("%d %lld", &n, &W))
{
memset(sw, , sizeof(weight));
memset(sv, , sizeof(value));
ans = ;
for (int i = ; i <= n; i++)
{
scanf("%lld %lld", &weight[i], &value[i]);
sw[i] = sw[i - ] + weight[i];
sv[i] = sv[i - ] + value[i];
}
dfs(n, , W);
printf("%lld\n", ans);
} return ;
}

NYOJ 1091 超大01背包(折半枚举)的更多相关文章

  1. nyoj 1091 还是01背包(超大数dp)

    nyoj 1091 还是01背包 描述 有n个重量和价值分别为 wi 和 vi 的物品,从这些物品中挑选总重量不超过W的物品,求所有挑选方案中价值总和的最大值 1 <= n <=40 1 ...

  2. CSU OJ PID=1514: Packs 超大背包问题,折半枚举+二分查找。

    1514: Packs Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 61  Solved: 4[Submit][Status][Web Board] ...

  3. Nyoj 三国志(dijkstra+01背包)

    描述 <三国志>是一款很经典的经营策略类游戏.我们的小白同学是这款游戏的忠实玩家.现在他把游戏简化一下,地图上只有他一方势力,现在他只有一个城池,而他周边有一些无人占的空城,但是这些空城中 ...

  4. hdu 5887 Herbs Gathering (dfs+剪枝 or 超大01背包)

    题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=5887 题解:这题一看像是背包但是显然背包容量太大了所以可以考虑用dfs+剪枝,贪心得到的不 ...

  5. E - Knapsack 2 题解(超大01背包)

    题目链接 题目大意 给你一n(n<=100)个物品,物品价值最大为1e3,物品体积最多为1e9,背包最大为1e9 题目思路 如果按照平常的背包来算那么时间复杂度直接O(1e11) 这个你观察就发 ...

  6. POJ 1837 Balance(01背包变形, 枚举DP)

    Q: dp 数组应该怎么设置? A: dp[i][j] 表示前 i 件物品放入天平后形成平衡度为 j 的方案数 题意: 有一个天平, 天平的两侧可以挂上重物, 给定 C 个钩子和G个秤砣. 2 4 - ...

  7. 中南林业大学校赛 I 背包问题 ( 折半枚举 || 01背包递归写法 )

    题目链接 题意 : 中文题 分析 :  价值和重量都太过于大,所以采用折半枚举的方法,详细可以看挑战的超大背包问题 由于 n <= 30 那么可以不必直接记录状态来优化,面对每个用例 直接采用递 ...

  8. (容量超大)or(容量及价值)超大背包问题 ( 折半枚举 || 改变 dp 意义 )

    题意 : 以下两个问题的物品都只能取有且只有一次 ① 给你 N 个物品,所有物品的价值总和不会超过 5000, 单个物品的价格就可达 10^10 ,背包容量为 B ② 给你 N (N ≤ 40 ) 个 ...

  9. nyoj 203 三国志 dijkstra+01背包

    题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=203 思路:先求点0到每个点的最短距离,dijkstra算法,然后就是01背包了 我奇怪的 ...

随机推荐

  1. jquery.cookie()方法

    jquery.cookie.js是一个轻量级的cookie 插件,可以读取.写入.删除 cookie. 首先包含jQuery的库文件,在后面包含 jquery.cookie.js 的库文件. < ...

  2. 周赛A题

    A  Time Limit:2000MS     Memory Limit:32768KB     64bit IO Format:%lld & %llu   Description By d ...

  3. A记录、CNAME记录、MX记录

    A 记录(Address)  (一句话:用来指定域名和服务器IP的对应关系) 是用来指定主机名(或域名)对应的IP地址记录.用户可以将该域名下的网站服务器指向到自己的web server上.同时也可以 ...

  4. HDU 3446 daizhenyang's chess

    http://acm.hdu.edu.cn/showproblem.php?pid=3446 题意:一个棋盘,有个KING,有一些能走的点,每次只能走到没走过的地方,没路可走的输,求先手是否必胜. 思 ...

  5. Keil uVISION2 自学教程

    Keil  uVISION2  是众多单片机应用开发软件中优秀的软件之一,它支持众多不同公司的 MCS-51 架构的芯片,它集编辑,编译,仿真等于一体,同时还支持.PLM.汇编和 C 语言的程序设计, ...

  6. Java实现KMP算法

    /**  * Java实现KMP算法  *   * 思想:每当一趟匹配过程中出现字符比较不等,不需要回溯i指针,   * 而是利用已经得到的“部分匹配”的结果将模式向右“滑动”尽可能远   * 的一段 ...

  7. UVA138 Street Numbers(数论)

    题目链接. 题意: 找一个n,和一个m(m < n),求使得1~m的和等于m~n的和,找出10组m,n 分析: 列出来式子就是 m*(m+1)/2 = (n-m+1)*(m+n)/2 化简后为 ...

  8. UVA11388 GCD LCM(数论)

    题目链接. 题意: 给定两个数,一个G,一个L,找出两个数a,b(a<=b),使得这两个数的最大公约数为G,最小公倍数为L,且(a最小). 分析: 当a,b存在时,a一定为G. 自己证了一下,数 ...

  9. 深入JS系列学习3

    深入JS系列学习3 深入理解JavaScript系列(9):根本没有"JSON对象"这回事! 很多JavaScript开发人员都错误地把JavaScript对象字面量(Object ...

  10. 铁通、长宽网络支付时“签名失败”问题分析及解决方案  [88222001]验证签名异常:FAIL[20131101100002-142]

    原文地址:http://bbs.tenpay.com/forum.php?mod=viewthread&tid=13723&highlight=%CC%FA%CD%A8 如果你的是铁通 ...