NYOJ 1091 超大01背包(折半枚举)
这道题乍一看是普通的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背包(折半枚举)的更多相关文章
- nyoj 1091 还是01背包(超大数dp)
nyoj 1091 还是01背包 描述 有n个重量和价值分别为 wi 和 vi 的物品,从这些物品中挑选总重量不超过W的物品,求所有挑选方案中价值总和的最大值 1 <= n <=40 1 ...
- CSU OJ PID=1514: Packs 超大背包问题,折半枚举+二分查找。
1514: Packs Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 61 Solved: 4[Submit][Status][Web Board] ...
- Nyoj 三国志(dijkstra+01背包)
描述 <三国志>是一款很经典的经营策略类游戏.我们的小白同学是这款游戏的忠实玩家.现在他把游戏简化一下,地图上只有他一方势力,现在他只有一个城池,而他周边有一些无人占的空城,但是这些空城中 ...
- hdu 5887 Herbs Gathering (dfs+剪枝 or 超大01背包)
题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=5887 题解:这题一看像是背包但是显然背包容量太大了所以可以考虑用dfs+剪枝,贪心得到的不 ...
- E - Knapsack 2 题解(超大01背包)
题目链接 题目大意 给你一n(n<=100)个物品,物品价值最大为1e3,物品体积最多为1e9,背包最大为1e9 题目思路 如果按照平常的背包来算那么时间复杂度直接O(1e11) 这个你观察就发 ...
- POJ 1837 Balance(01背包变形, 枚举DP)
Q: dp 数组应该怎么设置? A: dp[i][j] 表示前 i 件物品放入天平后形成平衡度为 j 的方案数 题意: 有一个天平, 天平的两侧可以挂上重物, 给定 C 个钩子和G个秤砣. 2 4 - ...
- 中南林业大学校赛 I 背包问题 ( 折半枚举 || 01背包递归写法 )
题目链接 题意 : 中文题 分析 : 价值和重量都太过于大,所以采用折半枚举的方法,详细可以看挑战的超大背包问题 由于 n <= 30 那么可以不必直接记录状态来优化,面对每个用例 直接采用递 ...
- (容量超大)or(容量及价值)超大背包问题 ( 折半枚举 || 改变 dp 意义 )
题意 : 以下两个问题的物品都只能取有且只有一次 ① 给你 N 个物品,所有物品的价值总和不会超过 5000, 单个物品的价格就可达 10^10 ,背包容量为 B ② 给你 N (N ≤ 40 ) 个 ...
- nyoj 203 三国志 dijkstra+01背包
题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=203 思路:先求点0到每个点的最短距离,dijkstra算法,然后就是01背包了 我奇怪的 ...
随机推荐
- 设计模式C++实现(1)——工厂模式
该文章转载自: http://blog.csdn.net/wuzhekai1985 软件领域中的设计模式为开发人员提供了一种使用专家设计经验的有效途径.设计模式中运用了面向对象编程语言的重要特性:封装 ...
- css margin collapse
css中存在margin collapse,即边界塌陷或边界重叠. http://www.w3cplus.com/css/understanding-bfc-and-margin-collapse.h ...
- 在动态引用DLL-A中,当参数是个实体,而实体的属性在另一个DLL-B中。。我们需要得到A这个实体并将其赋值,并将赋值的实体传人DLL-A的方法中。
string strPath = HttpContext.Current.Server.MapPath("/开放式DLL"); DirectoryInfo df = new Dir ...
- mongodb教程二
MongoDB 创建数据库: MongoDB 创建数据库的语法格式如下: use DATABASE_NAME 如果数据库不存在,则创建数据库,否则切换到指定数据库. 如果你想查看所有数据库,可以使用 ...
- Java中堆内存(heap)和栈内存(stack)的区别
在Java代码中,常常会使用到这样的类的声明实例化: Person per = new Person(); //这其实是包含了两个步骤,声明和实例化 Person per = null; //声明一个 ...
- 遇到个鬼,在WIN08的DELL R710上安装CENTOS 63,无法格式化以前的硬盘分区,安装无法进行下去。
遇到个鬼,在WIN08的DELL R710上安装CENTOS 63,无法格式化以前的硬盘分区,安装无法进行下去. 我下面类似的办法来解决,就是---进行在安装过程中,用快捷键:Ctrl+Alt+F2到 ...
- 调用系统API还是很高效的,不必担心性能
代码如下: void MainWindow::on_pushButton_2_clicked() { QTime total; total.start(); ; ; i<=*; i++) { Q ...
- POJPower Network (最大流)
题目链接. 分析: 这题描述的可不是一般的复杂. 其时就是很多源点.很多汇点,使尽量多流量的到达汇点. 因为有很多源点,就再设一个源点(0号),使得0号到其它源点的容量为其它源点的初始量,同样设一汇点 ...
- 怎样在WIN7系统下安装IIS
http://jingyan.baidu.com/article/19192ad853224ce53f570748.html
- cf591A Wizards' Duel
A. Wizards' Duel time limit per test 2 seconds memory limit per test 256 megabytes input standard in ...