In Java, how do I create a bitmap to solve "knapsack quandary" - java

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.

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.

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 to 2^N - 1, and try each one.
Assuming you have less that 32 numbers in the array, you essentially have an outer loop like this:
int numberOfCombinations = (1 << numbers.length - 1) - 1;
for (int i = 0; i < numberOfCombinations; ++i) { ... }
for each value of i, you need to go over each number in numbers, deciding to add or skip based on shifts and bitmasks of i.

So the task is to what an algorithm that, given a set A of non-negative numbers and a goal value k, determines whether there is a subset of A such that the sum of its elements is k.
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:
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];
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 a boolean[] 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.

I think you need something like this:
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
}
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, as int 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.

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:
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;
}
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:
map: 1 0 0 1 1 1 0 1
---------------
indexes: 7 6 5 4 3 2 1 0
To test the value for index 4 we would need a bit mask that looks like the following:
mask: 0 0 0 1 0 0 0 0
---------------
indexes: 7 6 5 4 3 2 1 0
To build the mask we simply start with 1 and shift it by 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
Once we have this we can apply the mask to the map and see if the value is set:
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
Since the result is != 0 we can tell that index 4 is included in the map.

Related

How do i find a value in an array in the most efficient way in that case?

NOTE: this algorithm should be done in the most efficient way that's a bad idea to have O(n^2)
This is a two dimensional array, now notice it's hard to see that in first glance but there is a hidden pattern on that array.
this array is actually sorted take a look at that image below you may see the pattern now.
the goal here is to make a function that searches for a value in an array that follows the exact pattern like the array i've showed you in the image and you need to return true if the value was found and also print the column and row where the value sits in the array.
if value wasn't found return false
here is an example
here is the function signature
public static boolean search(int [][]mat,int num){
//Code Here
}
let's say we are looking for the value 22 in that array(the same array in the image)
int [][]arr= {{1,3,7,9},{6,4,15,11},{36,50,21,22},{60,55,30,26}}
search(arr,22); //Returns true and also will be printed "row = 2 col = 3"
search(arr,86); //Returns false
The indices i and j into your matrix can be computed from a single linear index ranging from 0 through 15. This will allow you to do a normal binary search just translating each index from 1D to 2D.
private static int i(int index) {
return iBit(index / 4) * 2 + iBit(index % 4);
}
private static int iBit(int part) {
return (part / 2) ^ (part % 2);
}
private static int j(int index) {
int temp = index / 2;
return temp / 4 * 2 + temp % 2;
}
It’s a bit tricky. So let’s check that the methods work:
for (int index = 0; index < 16; index++) {
System.out.format("%2d -> %d %d%n", index, i(index), j(index));
}
Output:
0 -> 0 0
1 -> 1 0
2 -> 1 1
3 -> 0 1
4 -> 2 0
5 -> 3 0
6 -> 3 1
7 -> 2 1
8 -> 2 2
9 -> 3 2
10 -> 3 3
11 -> 2 3
12 -> 0 2
13 -> 1 2
14 -> 1 3
15 -> 0 3
The numbers agree with the pattern in the question.
NOTE: this algorithm should be done in the most efficient way that's a bad idea to have O(n^2)
It’s really nonsense. Big-O is defined based on the behaviour as the input size grows towards infinity. 16 does not grow towards infinty. Nor does 4. When the matrix size is constant, even a simple linear search will be O(1).

Find name in Arraylist, then transfer contents to an array?

I want to find my name in an ArrayList of students, then transfer my selection of 50 choices to a new array called myChoices (will later be compared against others for matches). The Student class contains a name and an ArrayList of choices. Here is the relevant loop:
int matches[] = new int[students.size()];
int myChoices[] = new int[students.get(0).getChoices().size()];
for(int i = 0; i < students.get(i).getChoices().size(); i++){
if(students.get(i).getName().equals("Garrett M")){
myChoices[i] = students.get(i).getChoices().get(i);
}
}
for(int i = 0; i < myChoices.length; i++){
System.out.println(myChoices[i]);
}
In the last loop, I'm just trying to print my choices, which come out as something like this:
0
0
0
0
0
0
0
0
0
1
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
(That's not 50, but you get the gist of it -- in the output there's about 49 zeros and one 1.) The actual output should begin with 1 and be a mixture of 0,1, and -1:
1 -1 1 1 1 1 0 1 1 0 0 0 1 1 0 1 0 0 1 1 0 0 0 0 0 1 1 0 0 1 0 1 0 0 1 0 1 -1 0 1 0 0 0 0 1 1 1 1 0 1
Any idea where I could be going wrong?
You are using the same index i for both the students List and the students.get(i).getChoices() List. That's probably wrong.
You probably need a nested loop:
for(int i = 0; i < students.size(); i++) { // iterate over the students to find the one
// having the required name
if(students.get(i).getName().equals("Garrett M")){
// iterate over the choices of the found student and collect them into the array
for (int j = 0; j < students.get(i).getChoices().size; j++) {
myChoices[j] = students.get(i).getChoices().get(j);
}
break;
}
}
By writing if statement inside loop you are only setting that particular element of mychoices[] array which matches with your name(Garrett M) rest all array element will remain as it is that is why you are getting 49 Zeros and 1 ones.
At times, imperative programming may turn out to be confusing with a lot of for loops. From ages, we have been using for far too many times in our code. With Java 8, one can code in declarative style. A code written in declarative style is more easy to read and understand.
Just adding to what #Eran has answered, I'll try to simplify the same solution using Java 8 Stream APIs. Some day, this might come in handy for you, if not today.
The problem in hand is to get the choices of a particular student and add those choices in an array(or Collection).
This can be done as follows:
List<Integer> myChoicesList = students.stream()
.filter(student -> student.getName().equals("Garrett M"))
.map(student -> student.getChoices())
.findFirst()
.get();
In the first step, convert your students list to a Java 8 Stream.
Remember Stream is an abstraction:
students.stream()
Next, filter out that one particular student in which you are
interested in:
filter(student -> student.getName().equals("Garrett M"))
At this point, the Stream contains that one student which was
filtered. But we are interested in the choices that this student
has. Hence, convert this stream of Student to a stream of
choices:
.map(student -> student.getChoices())
Now that you have your choices, you can perform your desired
operations on them. That's it!! Done!!
findFirst().get();
This will give you a List<Integer>. Later you can convert this collection to an Integer array as:
Integer[] myChoices = myChoicesList.toArray(new Integer[myChoicesList.size()]);
Note: I've designed this snippet assuming that, getChoices() method from Student class returns a List<Integer> containing choices of that Student.

Bitwise operations to remove specific bits expressed as a mask

As part of a serial data protocol decoder, I must decode data that has sync bits inserted (bits that are not part of the data and are always '1'). I need to remove the sync bits and assemble the data by shifting the remaining bits left. Each 32-bit word has a different pattern of sync bits. I know what the patterns are, but I cannot come up with a generalized was of removing the sync bits.
For example, I might have a bit pattern like this (just showing 12 bits for example):
0 1 1 1 1 0 0 1 1 0 1 1
I know that some of those bits are sync bits, specifically those that are '1' in this mask:
0 0 1 1 0 0 0 0 1 0 0 1
The resulting data should be those data bits with a '0' in the corresponding mask, shifted to remove the sync bits, padded right with zeros. The mask above could be understood as "take first 2 bits, skip next 2 bits, take next 4 bits, skip next bit, take 2 bits, skip 1 bit".
E.g I should end up with:
0 1 1 0 0 1 0 1 0 0 0 0
Trying to do this in Java but I don't see any bit mask/shift operations that would make this work.
Best method I could come up with (does not left align the results, but that is OK for my purposes):
private static final int MSB_ONLY = 0x80000000;
private static int squeezeBits(int data, int mask) {
int v = 0;
for (int i=0; i<32; i++) {
if ((mask & MSB_ONLY) != MSB_ONLY) {
// There is a 0 in the mask, so we want this data bit
v = (v << 1) | ((data & MSB_ONLY) >>> 31);
}
else {
// Throw bit away
}
mask = mask << 1;
data = data << 1;
}
return v;
}

Create and fill a variable-sized binary truth table

I am trying solve the 0/1 Knapsack problem through brute force. The simplest (it seems) way to do it would be to set up a 2d matrix with 1's and 0's signifying present and non-present in the knapsack, respectively. The parameters would be the number of items (ie: columns), so then the rows should be 2^numOfItems. But since the number of items isn't constant, I can't think of how to fill the matrix. I was told that bit-shifting would work, but I do not understand how that works. Can someone point me in the right direction?
EDIT: by truth table I mean the 'A' part of one of these: http://www.johnloomis.org/ece314/notes/devices/binary_to_BCD/bcd03.png
You don't have to store all the bit sequences in a matrix, it's unnecessary and will waste way too much memory. You can simply use an integer to denote the current set. The integer will go from 0 to 2^n-1 where n is the number of elements that you can choose from. Here's the basic idea.
int max = (1 << n);
for(int set = 0; set < max; set++)
{
for(int e = 0; e < n; e++)
{
if((set & (1 << e)) != 0)
//eth bit is 1 means that the eth item is in our set
else
// eth element will not be put in the knapsack
}
}
The algorithm relies on logical left bit shifting. (1 << n) means that we will shift 1, n positions to the left by padding zeros to the right side of the number. So for example, if we represent 1 as an 8-bit number 00000001, (1 << 1) == 00000010, (1 << 2) == 00000100, etc. The bitwise-and operator is an operator that takes two arguments, and "ands" every two bits that have the same index. So if we have 2 bit-strings of length n each, bit zero will be anded with bit 0, bit 1 with bit 1, etc. The output of & is a 1 if and only if both bits are 1s, otherwise it's 0. Why is this useful?? we need it to test bits. For example, assume that we have some set represented as a bit-string, and we want to determine if the ith bit in the bit-set is one or a zero. We can do that by using a shift left operation followed by a bitwise-and operation.
Example
Set = 00101000
we want to test Set(3) (remember that the rightmost bit is bit 0)
We can do that by shifting 1 3 places to the left, so it becomes 00001000. Then we "and" the shifted 1 with the set
00101000
&
00001000
---------
00001000
As you can see, if the bit I am testing is a 1, then the output of the & will be non zero, otherwise it'll be zero.

check number present in a sequences

I am writing a program which I found on a coding competition website, I have sort of figured out how to solve the problem but, I am stuck on a math part of it, I am completely diluting the problem and showing what I need.
first I need to check if a number is part of a sequence, my sequence is 2*a+1 where a is the previous element in the sequence or 2^n-1 to get nth item in the sequence. so it is 1,3,7,15,31,63...
I don't really want to create the whole sequence and check if a number is present, but I am not sure what a quicker method to do this would be.
Second if I am given a number lets say 25, I want to figure out the next highest number in my sequence to this number. So for 25 it would be 31 and for 47 it would be 63, for 8 it would be 13.
How can i do these things without creating the whole sequence.
I have seen similar questions here with different sequences but I am still not sure how to solve this
Start by finding the explicit formula for any term in your sequence. I'm too lazy to write out a proof, so just add 1 to each term in your sequence:
1 + 1 = 2
3 + 1 = 4
7 + 1 = 8
15 + 1 = 16
31 + 1 = 32
63 + 1 = 64
...
You can clearly see that a_n = 2^n - 1.
To check if a particular number is in your sequence, assume that it is:
x = 2^n - 1
x + 1 = 2^n
From Wikipedia:
The binary representation of integers makes it possible to apply a
very fast test to determine whether a given positive integer x is a
power of two:
positive x is a power of two ⇔ (x & (x − 1)) equals to zero.
So to check, just do:
bool in_sequence(int n) {
return ((n + 1) & n) == 0;
}
As #Blender already pointed out your sequence is essentially 2^n - 1, you can use this trick if you use integer format to store it:
boolean inSequence(int value) {
for (int i = 0x7FFF; i != 0; i >>>= 1) {
if (value == i) {
return true;
}
}
return false;
}
Note that for every elements in your sequence, its binary representation will be lots of 0s and then lots of 1s.
For example, 7 in binary is 0000000000000000000000000000111 and 63 in binary is 0000000000000000000000000111111.
This solution starts from 01111111111111111111111111111111 and use an unsigned bitshift, then compare if it is equal to your value.
Nice and simple.
How to find the next higher number :
For example, we get 19 ( 10011 ) , should return 31 (11111)
int findNext(int n){
if(n == 0) return 1;
int ret = 2; // start from 10
while( (n>>1) > 0){ // end with 100000
ret<<1;
}
return ret-1;
}

Categories