我正处于我的第一个编程课程中,现在我很困难。基本上,我们正在做的是从文本文件中获取16个值(在第一行代码中),并且在第二行代码上有一个值。我们将这16个值读入数组,并将第2行值设置为目标。我对那部分没有任何问题。
但是,我遇到麻烦的是创建一个位图来测试16个值的每个可能子集,它们等于目标数量。
IE,说我们有这些数字:
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
然后我们测试该子集以查看它是否等于“目标”数字。
我们只允许在问题中使用一个数组,并且我们不允许使用数学类(还没有使用它)。
我理解这个概念,我知道我需要实现移位运算符和逻辑&
符号,但我真的很茫然。我非常沮丧,我只是想知道是否有人可以给我任何提示。
答案 0 :(得分:0)
要在int中生成所有可能的位模式,因此该位图定义的所有可能子集都只需要在1处启动int并将其递增到unsigned short int可以容纳的最高值(全1) )。在每个内循环的末尾,将总和与目标进行比较。如果它匹配,你有一个解决方案子集 - 打印出来。如果没有,请尝试下一个子集。 有人可以帮忙解释如何去做吗?我理解这个概念,但缺乏如何实现它的知识。
答案 1 :(得分:0)
好的,所以你可以获得一个阵列。据推测,该数组包含第一组数据。 所以你的方法不需要任何额外的数组。
在这种情况下,位向量只是一个心理模型构造。这个想法是这样的:如果你尝试了所有可能的组合(注意,不是排列),那么你将找到与你的目标最接近的总和。所以假设你有N个数字。这意味着您有2^N
种可能的组合。
位向量方法是将每个组合编号为0
到2^N - 1
,然后尝试每个组合。
假设你在数组中少了32个数字,你基本上就有这样一个外部循环:
int numberOfCombinations = (1 << numbers.length - 1) - 1;
for (int i = 0; i < numberOfCombinations; ++i) { ... }
对于i
的每个值,您需要检查numbers
中的每个数字,根据i
的移位和位掩码决定添加或跳过。
答案 2 :(得分:0)
因此,任务是给定一组A
非负数和目标值k
的算法,确定是否存在A
的子集,以便其元素之和为k
。
我使用A上的感应来接近这一点,跟踪哪些数字&lt; = k是到目前为止处理的元素集的子集的总和。那就是:
boolean[] reachable = new boolean[k+1];
reachable[0] = true;
for (int a : A) {
// compute the new reachable
// hint: what's the relationship between subsets of S and S \/ {a} ?
}
return reachable[k];
从数学上讲,位图是将一系列数字映射到{0,1}的函数。 boolean[]
将数组索引映射到布尔值。所以可以调用boolean[]
位图。
使用boolean[]
的一个不利之处是您必须单独处理每个数组元素。相反,可以使用长保持64位,并使用位移和屏蔽操作一次处理64个“数组”元素。但是这种微优化很容易出错而且很复杂,所以在代码中通常不应该做到可靠和可维护。
答案 3 :(得分:0)
我认为你需要这样的东西:
public boolean equalsTarget( int bitmap, int [] numbers, int target ) {
int sum = 0; // this is the variable we're storing the running sum of our numbers
int mask = 1; // this is the bitmask that we're using to query the bitmap
for( int i = 0; i < numbers.length; i++ ) { // for each number in our array
if( bitmap & mask > 0 ) { // test if the ith bit is 1
sum += numbers[ i ]; // and add the ith number to the sum if it is
}
mask <<= 1; // shift the mask bit left by 1
}
return sum == target; //if the sum equals the target, this bitmap is a match
}
您的其余代码非常简单,您只需将位图的每个可能值(1..65535)提供给此方法并对结果执行操作。
P.s。:请确保您完全理解解决方案,而不仅仅是复制它,否则您只是在欺骗自己。 :)
Pps:在这种情况下使用int
有效,因为int
是32位宽,我们只需要16。如果需要所有位,请注意按位操作,因为所有原始整数类型(byte,short,int,long)用Java签名。
答案 4 :(得分:0)
解决这个问题有几个步骤。首先,您需要枚举所有可能的位图。正如其他人指出的那样,你可以通过递增0到2 ^ n - 1的整数来轻松完成。
一旦你有了这个,就可以遍历所有可能的位图,你只需要一种方法来获取该位图并将其“应用”到一个数组中,以生成地图所代表的所有索引上的元素之和。以下方法是如何执行此操作的示例:
private static int bitmapSum(int[] input, int bitmap) {
// a variable for holding the running total
int sum = 0;
// iterate over each element in our array
// adding only the values specified by the bitmap
for (int i = 0; i < input.length; i++) {
int mask = 1 << i;
if ((bitmap & mask) != 0) {
// If the index is part of the bitmap, add it to the total;
sum += input[i];
}
}
return sum;
}
此函数将采用整数数组和位图(表示为整数),并返回数组中所有元素的总和,其索引存在于掩码中。
此功能的关键是能够确定给定的索引是否实际位于位图中。这是通过首先为所需索引创建一个位掩码,然后将该掩码应用于位图来测试是否设置了该值来实现的。
基本上我们想要构建一个整数,其中只有一位被设置而所有其他位都为零。然后,我们可以使用位图按位AND该掩码,并通过将结果与0进行比较来测试是否设置了特定位置。
假设我们有一个如下所示的8位地图:
map: 1 0 0 1 1 1 0 1
---------------
indexes: 7 6 5 4 3 2 1 0
要测试索引4的值,我们需要一个如下所示的位掩码:
mask: 0 0 0 1 0 0 0 0
---------------
indexes: 7 6 5 4 3 2 1 0
要构建蒙版,我们只需从1开始并将其移动N:
1: 0 0 0 0 0 0 0 1
shift by 1: 0 0 0 0 0 0 1 0
shift by 2: 0 0 0 0 0 1 0 0
shift by 3: 0 0 0 0 1 0 0 0
shift by 4: 0 0 0 1 0 0 0 0
一旦我们有了这个,我们可以将蒙版应用于地图,看看是否设置了值:
map: 1 0 0 1 1 1 0 1
mask: 0 0 0 1 0 0 0 0
---------------
result of AND: 0 0 0 1 0 0 0 0
由于结果是!= 0,我们可以判断索引4是否包含在地图中。