Reputation: 635
I've been trying to figure out how to approach this, can someone give me an idea of an algorithm or a set of steps to solve this? I'm really stumped. Code isn't necessary. I'm planning to solve it Python3, C and Rust.
Consider four numbers: a, b, c, and k. You must change at most k bits in a and b to form numbers a' and b' satisfying the equation a' | b' = c. | denotes bitwise OR operation.
If no such value exists, return -1 instead. In case of multiple solutions, make a' as small as possible; if there are still multiple solutions, make b' as small as possible.
If the number of bits changed in a is k.a (similarly k.b for b), then k.a + k.b <= k .
Upvotes: 2
Views: 170
Reputation: 11434
I assume the desired results are XOR-masks, ie. numbers with 1 where bits should be changed and 0 where they should be left untouched (so that a XOR amask = a'
and b XOR bmask = b'
)
Just for completeness, the result of a' | b'
has 1 bits where either a', or b', or both have 1, else 0.
There first, absolutely necessary, condition for a' | b' = c
is that neither a' nor b' have 1 bits where c has 0 bits. In other words, to get the first amask and bmask, you can take a and b and set every bit to 0 where c has 1. In other words again, to get the first amask and bmask, you can take a and b and set every bit to 0 where the binary complement of c has 0.
amask = a & (~c)
bmask = b & (~c)
Now count how many bit are 1 in amask and bmask (either with a naive loop, or with one of the many popcount functions online), and subtract this from your k. If k gets negative, there is no solution (return -1).
The second part requires that you find bits where both a and b are 0 but c is 1. To put it short:
temp_mask = c & ((a XOR amask) | (b XOR bmask))
temp_mask are the bits you need to set to 1 in either a or b (which one depends on the "smallest" requirement. But first, pop-count temp_mask too, if the result is larger than your remaining k, there is no solution (return -1).
The next step is simple:
amask = amask | temp_mask
The previous amask had 1 where c was 0, this statement now won't overlap anything.
Now, you have at least one solution for a' | b' = c
, that is
(a XOR amask) | (b XOR bmask) = c
But there could still be another one with a smaller a, right?
That's not very hard too: Each bit which is 1 in (a XOR amask)
but 0 in (b XOR bmask)
can be "moved", ie. make it 0 in (a XOR amask)
and 1 in (b XOR bmask)
. The result c will be the same, but the numeric value of (a XOR amask)
will be smaller (possibly, worst case it stays the same).
temp_mask = (a XOR amask) & (~(b XOR bmask))
amask = amask XOR temp_mask
bmask = bmask XOR temp_mask
For implementing this, pay attention to unsigned
and int sizes.
Full pseudocode:
amask = a & (~c)
bmask = b & (~c)
temp_mask = c & ((a XOR amask) | (b XOR bmask))
amask = amask | temp_mask
temp_mask = (a XOR amask) & (~(b XOR bmask))
amask = amask XOR temp_mask
bmask = bmask XOR temp_mask
Upvotes: 2
Reputation: 18803
The slow way:
Make it fast using this information:
Find extra bits in a: a & ~c (need to be removed in any case)
Find extra bits in b: b & ~c (need to be removed in any case)
Find missing bits: ~(a|b) & c (need to be set in b' to keep a' small)
Feasible if the sum of the corresponding bit counts is <= k.
Upvotes: 1