RabbitFarm
2022-11-27
Flipping to Redistribute
The examples used here are from the weekly challenge problem statement and demonstrate the working solution.
Part 1
You are given a positive integer, $n. Write a script to find the binary flip.
Solution
use v5.36;
sub int2bits{
my($n) = @_;
my @bits;
while($n){
my $b = $n & 1;
unshift @bits, $b;
$n = $n >> 1;
}
return @bits
}
sub binary_flip{
my($n) = @_;
my @bits = int2bits($n);
@bits = map {$_^ 1} @bits;
return oct(q/0b/ . join(q//, @bits));
}
MAIN:{
say binary_flip(5);
say binary_flip(4);
say binary_flip(6);
}
Sample Run
$ perl perl/ch-1.pl
2
3
1
Notes
There was once a time when I was positively terrified of bitwise operations. Anything at that level seemed a bit like magic. Especially spooky were the bitwise algorithms detailed in Hacker's Delight! Anyway, has time has gone on I am a bit more confortable with these sorts of things. Especially when, like this problem, the issues are fairly straightforward.
The code here does the following:
converts a given integer into an array of bits via
int2bits()
flips the bits using an xor operation (the
map
inbinary_flip()
)converts the array of flipped bits to the decimal equivalent via
oct()
which, despite the name, handles any decimal, binary, octal, and hex strings as input.
Part 2
You are given a list of integers greater than or equal to zero, @list. Write a script to distribute the number so that each members are same. If you succeed then print the total moves otherwise print -1.
Solution
use v5.36;
use POSIX;
sub equal_distribution{
my(@integers) = @_;
my $moves;
my $average = unpack("%32I*", pack("I*", @integers)) / @integers;
return -1 unless floor($average) == ceil($average);
{
map{
my $i = $_;
if($integers[$i] > $average && $integers[$i] > $integers[$i+1]){$integers[$i]--; $integers[$i+1]++; $moves++}
if($integers[$i] < $average && $integers[$i] < $integers[$i+1]){$integers[$i]++; $integers[$i+1]--; $moves++}
} 0 .. @integers - 2;
redo unless 0 == grep {$average != $_} @integers;
}
return $moves;
}
MAIN:{
say equal_distribution(1, 0, 5);
say equal_distribution(0, 2, 0);
say equal_distribution(0, 3, 0);
}
Sample Run
$ perl perl/ch-2.pl
4
-1
2
Notes
The rules that must be followed are:
1) You can only move a value of '1' per move
2) You are only allowed to move a value of '1' to a direct neighbor/adjacent cell.
First we compute the average of the numbers in the list. Provided that the average is a
non-decimal (confirmed by comparing floor
to ceil
) we know we can compute the
necessary "distribution".
The re-distribution itself is handled just by following the rules and continuously looping until all values in the list are the same.
References
posted at: 19:04 by: Adam Russell | path: /perl | permanent link to this entry