在Java中,如何创建位图来解决“背包困境”?
我正在学习第一门编程课程,现在我陷入了困境。基本上,我们所做的是从文本文件(第一行代码)中获取 16 个值,第二行代码中有一个值。我们将这 16 个值读入一个数组,并将第二行值设置为目标。我对那部分没有任何问题。
但是,我遇到的麻烦是创建一个位图来测试 16 个值的每个可能的子集,即等于目标数。
即,假设我们有这些数字:
12 15 20 4 3 10 17 12 24 21 19 33 27 11 25 32
然后我们将每个值对应于一个位图
0 1 1 0 0 0 0 1 1 1 0 1 0 0 1 0
然后我们只接受以“1”为谓词的值
15 20 12 24 21 33 25
然后我们测试该子集以查看它是否等于“目标”数字。
我们只允许在问题中使用一个数组,并且不允许我们使用数学类(还没有接触到它)。
我理解这个概念,并且我知道我需要实现移位运算符和逻辑 &
符号,但我真的很茫然。我很沮丧,我只是想知道是否有人可以给我任何提示。
I'm in my first programming course and I'm quite stuck right now. Basically, what we are doing is we take 16 values from a text file (on the first line of code) and there is a single value on the second line of code. We read those 16 values into an array, and we set that 2nd line value as our target. I had no problem with that part.
But, where I'm having trouble is creating a bitmap to test every possible subset of the 16 values, that equal the target number.
IE, say we had these numbers:
12 15 20 4 3 10 17 12 24 21 19 33 27 11 25 32
We then correspond each value to a bitmap
0 1 1 0 0 0 0 1 1 1 0 1 0 0 1 0
Then we only accept the values predicated with "1"
15 20 12 24 21 33 25
Then we test that subset to see if it equals the "target" number.
We are only allowed to use one array in the problem, and we aren't allowed to use the math class (haven't gotten to it yet).
I understand the concept, and I know that I need to implement shifting operators and the logical &
sign, but I'm truly at a loss. I'm very frustrated, and I just was wondering if anybody could give me any tips.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
要生成 int 内所有可能的位模式以及该位图定义的所有可能的子集,只需将 int 从 1 开始,并不断将其递增到无符号短 int 可以容纳的最高可能值(全 1)。在每个内部循环结束时,将总和与目标进行比较。如果匹配,您将获得一个解决方案子集 - 将其打印出来。如果没有,请尝试下一个子集。
有人可以帮助解释如何去做吗?我理解这个概念,但缺乏如何实施它的知识。
To generate all possible bit patterns inside an int and thus all possible subsets defined by that bit map would simply require you to start your int at 1 and keep incrementing it to the highest possible value an unsigned short int can hold (all 1s). At the end of each inner loop, compare the sum to the target. If it matches, you got a solution subset - print it out. If not, try the next subset.
Can someone help to explain how to go about doing this? I understand the concept but lack the knowledge of how to implement it.
好的,所以您可以使用一个数组。据推测,该数组保存第一组数据。
所以你的方法不需要有任何额外的数组。
在这种情况下,位向量只是一个心理模型构造。这个想法是这样的:如果你尝试每一种可能的组合(注意,不是排列),那么你将找到最接近你的目标的总和。假设你有 N 个数字。这意味着您有
2^N
种可能的组合。位向量方法是用
0
到2^N - 1
对每个组合进行编号,并尝试每个组合。假设数组中的数字少于 32 个,则本质上有一个如下所示的外循环:
对于
i
的每个值,您需要遍历numbers
中的每个数字,根据i
的移位和位掩码决定添加或跳过。OK, so you are allowed one array. Presumably, that array holds the first set of data.
So your approach needs to not have any additional arrays.
The bit-vector is simply a mental model construct in this case. The idea is this: if you try every possible combination (note, NOT permutation), then you are going to find the closest sum to your target. So lets say you have N numbers. That means you have
2^N
possible combinations.The bit-vector approach is to number each combination with
0
to2^N - 1
, and try each one.Assuming you have less that 32 numbers in the array, you essentially have an outer loop like this:
for each value of
i
, you need to go over each number innumbers
, deciding to add or skip based on shifts and bitmasks ofi
.因此,任务是设计一种算法,在给定一组非负数
A
和目标值k
的情况下,确定是否存在A 的子集
使得其元素之和为k
。我会使用 A 上的归纳法来解决这个问题,跟踪哪些数字 <= k 是迄今为止处理的元素集的子集的总和。也就是说:
从数学上来说,位图是将一系列数字映射到 {0, 1} 的函数。
boolean[]
将数组索引映射到布尔值。因此,我们可以将boolean[]
称为位图。使用 boolean[] 的一个缺点是您必须单独处理每个数组元素。相反,我们可以使用 long 保存 64 位,并使用位移位和掩码操作来一次处理 64 个“数组”元素。但这种微优化很容易出错,而且相当复杂,因此通常不会在应该可靠和可维护的代码中完成。
So the task is to what an algorithm that, given a set
A
of non-negative numbers and a goal valuek
, determines whether there is a subset ofA
such that the sum of its elements isk
.I'd approach this using induction over A, keeping track of which numbers <= k are sums of a subset of the set of elements processed so far. That is:
A bitmap is, mathematically speaking, a function mapping a range of numbers onto {0, 1}. A
boolean[]
maps array indices to booleans. So one could call aboolean[]
a bitmap.One disadvanatage of using a
boolean[]
is that you must process each array element individually. Instead, one could use that a long holds 64 bits, and use bitshifting and masking operations to process 64 "array" elements at a time. But that sort of microoptimization is error-prone and rather involved, so not commonly done in code that should be reliable and maintainable.我认为你需要这样的东西:
你的代码的其余部分相当简单,你只需将位图(1..65535)的每个可能值输入到这个方法中并根据结果进行操作。
PS:请确保你完全理解了解决方案,而不是简单地复制它,否则你就是在欺骗自己。 :)
Pps:在这种情况下使用
int
是可行的,因为int
是 32 位宽,而我们只需要 16 位。请小心按位运算,但如果您需要所有位,因为所有原始整数类型(byte、short、int、long)在 Java 中都是有符号的。I think you need something like this:
The rest of your code is fairly simple, you just feed every possible value of your bitmap (1..65535) into this method and act on the result.
P.s.: Please make sure that you fully understand the solution and not just copy it, otherwise you're just cheating yourself. :)
P.p.s: Using
int
works in this case, asint
is 32 bit wide and we only need 16. Be careful with bitwise operations though if you need all the bits, as all primitive integer types (byte, short, int, long) are signed in Java.解决这个问题有几个步骤。首先,您需要枚举所有可能的位图。正如其他人指出的那样,您可以通过将整数从 0 增加到 2^n - 1 来轻松地做到这一点。
一旦您有了它,您就可以迭代所有可能的位图,您只需要一种方法来获取该位图并“应用" 将其转换为一个数组,以生成映射所表示的所有索引处的元素之和。以下方法是如何执行此操作的示例:
此函数将采用整数数组和位图(表示为整数),并返回数组中索引出现在掩码中的所有元素的总和。
该函数的关键是能够确定给定索引是否确实位于位图中。这是通过首先为所需索引创建位掩码,然后将该掩码应用于位图以测试是否设置了该值来完成的。
基本上我们想要构建一个整数,其中仅设置了一位,而所有其他位均为零。然后我们可以将该掩码与位图进行按位与运算,并通过将结果与 0 进行比较来测试是否设置了特定位置。
假设我们有一个如下所示的 8 位图:
要测试索引 4 的值,我们需要一个位掩码如下所示:
要构建掩码,我们只需从 1 开始并将其移位 N:
一旦我们有了这个,我们就可以将掩码应用于映射并查看该值是否已设置:
因为结果是 != 0我们可以看出索引 4 已包含在内在地图中。
There are a couple steps in solving this. First you need to enumerate all the possible bit maps. As others have pointed out you can do this easily by incrementing an integer from 0 to 2^n - 1.
Once you have that, you can iterate over all the possible bit maps you just need a way to take that bit map and "apply" it to an array to generate the sum of the elements at all indexes represented by the map. The following method is an example of how to do that:
This function will take an integer array and a bit map (represented as an integer) and return the sum of all the elements in the array whose index are present in the mask.
The key to this function is the ability to determine if a given index is in fact in the bit map. That is accomplished by first creating a bit mask for the desired index and then applying that mask to the bit map to test if that value is set.
Basically we want to build an integer where only one bit is set and all the others are zero. We can then bitwise AND that mask with the bit map and test if a particular position is set by comparing the result to 0.
Lets say we have an 8-bit map like the following:
To test the value for index 4 we would need a bit mask that looks like the following:
To build the mask we simply start with 1 and shift it by N:
Once we have this we can apply the mask to the map and see if the value is set:
Since the result is != 0 we can tell that index 4 is included in the map.