23
\$\begingroup\$

Challenge

Given a list of positive integers, find if there exists a permutation where taking up to one bit from each of the integers, a binary number consisting of all 1s can be created.

The number of bits in the resulting binary number is equal to the highest MSB in the list of integers.

Output

Your code must output or return a truthy/falsey value indicating if such a permutation exists.

Examples

Truthy:

With the list [4, 5, 2], and its binary representation [100, 101, 10], we can use the third, first, and second bits, respectively, to create 111:

4  ->  100  ->  100  ->  1
5  ->  101  ->  101  ->    1
2  ->  010  ->  010  ->   1
Result                   111

With the list [3, 3, 3], all of the numbers have both first and second bits set as 1, so we can take our pick with a number to spare:

3  ->  11  ->  11  ->  1
3  ->  11  ->  11  ->   1
3  ->  11  ->  11  ->
Result                 11

Falsey:

With the list [4, 6, 2], none of the numbers have the first bit set as 1, so the binary number cannot be created:

4  ->  100
6  ->  110
2  ->  010

With the list [1, 7, 1], only one of the numbers has the second and third bits set as 1, and the number cannot be created:

1  ->  001
7  ->  111
1  ->  001

Obviously, if the maximum number of set bits exceeds the number of integers, the result number can never be created.

Test cases

Truthy:

[1]
[1, 2]
[3, 3]
[3, 3, 3]
[4, 5, 2]
[1, 1, 1, 1]
[15, 15, 15, 15]
[52, 114, 61, 19, 73, 54, 83, 29]
[231, 92, 39, 210, 187, 101, 78, 39]

Falsey:

[2]
[2, 2]
[4, 6, 2]
[1, 7, 1]
[15, 15, 15]
[1, 15, 3, 1]
[13, 83, 86, 29, 8, 87, 26, 21]
[154, 19, 141, 28, 27, 6, 18, 137]

Rules

Standard loopholes are forbidden. As this is , shortest entry wins!

\$\endgroup\$
  • \$\begingroup\$ There's a theorem that might help with this… \$\endgroup\$ – Not a tree Nov 6 '17 at 6:25
  • \$\begingroup\$ Welcome to PPCG! Nice first challenge! \$\endgroup\$ – Mr. Xcoder Nov 6 '17 at 6:54
  • \$\begingroup\$ @Notatree: Well, how nice. I can use the shortest code to find me a wife. \$\endgroup\$ – Antti29 Nov 6 '17 at 6:55
  • \$\begingroup\$ Added to my index of graph problems as bipartite matching. \$\endgroup\$ – Peter Taylor Nov 6 '17 at 9:04

16 Answers 16

8
\$\begingroup\$

Jelly, 11 bytes

BUT€ŒpṬz0PẸ

Try it online!

How it works

BUT€ŒpṬz0PẸ  Main link. Argument: A (array)

             Example: A = [4, 5, 2]
B            Binary; convert each n in A to base 2.
                      [[1, 0, 0], [1, 0, 1], [1, 0]]
 U           Upend; reverse all arrays of binary digits.
                      [[0, 0, 1], [1, 0, 1], [0, 1]]
  T€         Truth each; for each binary array, get all indices of 1's.
                      [[3], [1, 3], [2]]
    Œp       Take the Cartesian product of all index arrays.
                      [[3, 1, 2], [3, 3, 2]
      Ṭ      Untruth; map each index array to a binary arrays with 1's at
             at the specified indices.
                      [[1, 1, 1], [0, 1, 1]]
       z0    Zip/transpose the resulting 2D array, filling shorter rows with 0's.
                      [[1, 0], [1, 1], [1, 1]]
         P   Take the columnwise product.
                      [1, 0]
          Ẹ  Any; yield 1 if any of the products is non-zero, 0 otherwise.
                      1
\$\endgroup\$
7
\$\begingroup\$

J, 30 bytes

All credit goes to my colleague Marshall.

Unnamed tacit prefix function.

[:+./ .*(1->./@${.|:)^:2@|:@#:

Try it online!

(@ is function composition)

#: antibase-2

|: transpose

()^:2 apply the following function twice:

1- Boolean negate

>./ the maximum

@ of the

$ axis lengths

{. take (padding with zeros) from

|: the transposed argument

+./ .*"crazy determinant magic"*

[: don't hook (no-op – serves to compose the previous part with the rest)


* In Marshall's words.

\$\endgroup\$
6
\$\begingroup\$

JavaScript (ES6), 104 ... 93 83 bytes

Returns 0 or 1.

f=(a,m=Math.max(...a),s=1)=>s>m|a.some((n,i)=>n&s&&f(b=[...a],m,s*2,b.splice(i,1)))

Test cases

f=(a,m=Math.max(...a),s=1)=>s>m|a.some((n,i)=>n&s&&f(b=[...a],m,s*2,b.splice(i,1)))

console.log('Truthy')
console.log(f([1]))
console.log(f([1, 2]))
console.log(f([3, 3]))
console.log(f([3, 3, 3]))
console.log(f([4, 5, 2]))
console.log(f([1, 1, 1, 1]))
console.log(f([15, 15, 15, 15]))
console.log(f([52, 114, 61, 19, 73, 54, 83, 29]))
console.log(f([231, 92, 39, 210, 187, 101, 78, 39]))

console.log('Falsy')
console.log(f([2]))
console.log(f([2, 2]))
console.log(f([4, 6, 2]))
console.log(f([1, 7, 1]))
console.log(f([15, 15, 15]))
console.log(f([1, 15, 3, 1]))
console.log(f([13, 83, 86, 29, 8, 87, 26, 21]))
console.log(f([154, 19, 141, 28, 27, 6, 18, 137]))

Method

Given the input array A = [a0, a1, ..., aN-1], we look for a permutation [ap[0], ap[1], ..., ap[N-1]] of A and an integer x ≤ N such that:

  • s = 1 + (ap[0] AND 20) + (ap[1] AND 21) + ... + (ap[x-1] AND 2x-1) = 2x
  • and s is greater than the greatest element m of A

Formatted and commented

f = (                 // f = recursive function taking:
  a,                  //   - a = array
  m = Math.max(...a), //   - m = greatest element in a
  s = 1               //   - s = current power of 2, starting at 1
) =>                  //
  s > m               // success condition (see above) which is
  |                   // OR'd with the result of this some():
  a.some((n, i) =>    // for each element n at position i in a:
    n & s &&          //   provided that the expected bit is set in n,
    f(                //   do a recursive call with:
      b = [...a],     //     b = copy of a
      m,              //     m unchanged
      s * 2,          //     s = next power of 2
      b.splice(i, 1)  //     the current element removed from b
    )                 //   end of recursive call
  )                   // end of some()
\$\endgroup\$
4
\$\begingroup\$

Husk, 14 bytes

SöV≡ŀToṁ∂Pmo↔ḋ

Try it online!

Explanation

SöV≡ŀToṁ∂Pmo↔ḋ  Implicit input, say [4,5,2].
          m  ḋ  Convert each to binary
           o↔   and reverse them: x = [[0,0,1],[1,0,1],[0,1]]
         P      Take all permutations of x
      oṁ∂       and enumerate their anti-diagonals in y = [[0],[0,1],[1,0,0],[1,1],[1]..
S    T          Transpose x: [[0,1,0],[0,0,1],[1,1]]
    ŀ           Take the range up to its length: z = [1,2,3]
                Then z is as long as the longest list in x.
 öV             Return the 1-based index of the first element of y
   ≡            that has the same length and same distribution of truthy values as z,
                i.e. is [1,1,1]. If one doesn't exist, return 0.
\$\endgroup\$
4
\$\begingroup\$

05AB1E, 23 22 20 bytes

-1 byte thanks to Mr.Xcoder

True: 1, False: 0

2вí0ζœεvyƶNè})DgLQ}Z

Try it online!

Explanations:

2вí0ζœεvyƶNè})DgLQ}Z   Full program (implicit input, e.g. [4, 6, 2])
2в                     Convert each to binary ([1,0,0], [1,1,0], [1,0])
  í                    Reverse each ([0,0,1], [0,1,1], [0,1])
   0ζ                  Zip with 0 as a filler ([0,0,0],[0,1,1],[1,1,0])
     œ                 Get all sublists permutations
      ε           }    Apply on each permutation...
       vyƶNè}            For each sublist...
        yƶ                  Multiply each element by its index
          Nè                Get the element at position == sublist index
             )           Wrap the result in a list
              DgLQ       1 if equal to [1,2,...,length of item]
                   Z   Get max item of the list (1 if at least 1 permutations fill the conditions)
                       -- implicit output
\$\endgroup\$
3
\$\begingroup\$

Wolfram Language (Mathematica), 65 bytes

Max[Tr/@Permutations[n=PadLeft[#~IntegerDigits~2]]]==Tr[1^#&@@n]&

Try it online!

Explanation

#~IntegerDigits~2

We start by converting all inputs to binary lists.

n=PadLeft[...]

Then we pad all those lists with zeros to the left to make the array rectangular. The result is stored in n for later.

Permutations[...]

Yay, brute force, let's get all possible permutations of the input.

Tr/@...

This gets the trace for each permutation, i.e. the sum of the diagonal elements in the permutation. In other words, we add up the MSB from the first number, the next-to-MSB from the second number and so on. If the permutation is valid, all of these will be 1 and there will be as many 1s as the largest input number is wide.

Max[...]

We get the maximum trace, because the trace can never be more than that of a valid permutation.

...==Tr[1^#&@@n]

The right-hand side is just a golfy version of Length @ First @ n, i.e. it gets the width of the rectangular array, and therefore the width of the largest input number. We want to make sure that the trace of some permutation is equal to this.

\$\endgroup\$
3
\$\begingroup\$

PHP, 255 243 160 bytes

-12 bytes, took out the sorting
-83 bytes (!) thanks to Titus

<?function f($a,$v=NULL,$b=[]){($v=$v??(1<<log(max($a),2)+1)-1)||die("1");if($p=array_pop($a))while($p-=$i)($b[$i=1<<log($p,2)]|$v<$i)||f($a,$v-$i,[$i=>1]+$b);}

Try it online!

Prints 1 for truthy, nothing for falsey.

Original version ungolfed:

<?php
unset($argv[0]);                                                   // remove filename from arguments
$max = pow(2,floor(log(max($argv),2))+1)-1;                        // get target number (all bits set to 1)
solve($argv,$max,[]);
function solve($array,$value,$bits){
  if(!$value){                                                     // if we've reached our target number (actually subtracted it to zero)
    die("1");                                                      // print truthy
  }
  if(count($array)){                                               // while there are arguments left to check
    $popped = array_pop($array);                                   // get the largest argument
    while($popped > 0 && ($mybit = pow(2,floor(log($popped,2))))){ // while the argument hasn't reached zero, get the highest power of 2 possible
      $popped -= $mybit;                                           // subtract power from argument
      if($value >= $mybit && !$bits[$i]){                          // if this bit can be subtracted from our argument, and we haven't used this bit yet
        $copy = $bits;                                             // create a copy to pass to the function
        $copy[$mybit] = 1;                                         // mark the bit as used in the copy
        solve($array,$value-$mybit,$copy);                         // recurse
      }
    }
  }
}
\$\endgroup\$
  • \$\begingroup\$ I haven´t tested it, but theses 158 bytes should do the same: function f($a,$v=NULL,$b=[]){($v=$v??(1<<log(max($a),2)+1)-1)||die("1");if($p=array_pop($a))while($p-=$i)($b[$i=1<<log($p,2)]|$v<$i)||f($a,$v-$i,[$i=>1]+$b);} \$\endgroup\$ – Titus Nov 7 '17 at 0:15
  • \$\begingroup\$ @Titus and thus we see how terrible I am at codegolf. And why most questions have a great answer by you in PHP. (and a few other languages). \$\endgroup\$ – Jo. Nov 7 '17 at 6:35
  • \$\begingroup\$ Terrible for now. That´s a pretty good answer; and golfing skills come with experience. \$\endgroup\$ – Titus Nov 7 '17 at 9:58
  • \$\begingroup\$ No need for the lengthy string notation, just use something else that translates to “1” but is not integer. For example a boolean true: die("1")die(!0). \$\endgroup\$ – manatwork Nov 8 '17 at 8:05
2
\$\begingroup\$

Lua 5.2, 85 bytes

m=math
x=function(...)print(bit32.bor(...)==2^(m.floor(m.log(m.max(...),2))+1)-1)end

This sets x to be a function that accepts a variable number of inputs (expected to be 32 bit integers), and prints to stdout either "true" or "false".

Usage:

x(13, 83, 86, 29, 8, 87, 26, 21) -- Prints "false"
\$\endgroup\$
  • 1
    \$\begingroup\$ Hmm, this seems to fail for some of the false test cases? [1,15,3,1] seems to return true instead of false for example. Here is your code the online compiler of TIO. The other two test cases that fail are [1,7,1] and [15,15,15]. All the other test cases output the correct results. \$\endgroup\$ – Kevin Cruijssen Nov 8 '17 at 13:05
2
\$\begingroup\$

PHP, 121 bytes

function f($a,$s=0){($v=array_pop($a))||(0|$g=log($s+1,2))-$g||die("1");for($b=.5;$v<=$b*=2;)$v&$b&&~$s&$b&&f($a,$s|$b);}

Try it online.

breakdown

function f($a,$s=0)
{
    ($v=array_pop($a))          # pop element from array
    ||                          # if nothing could be popped (empty array)
    (0|$g=log($s+1,2))-$g       # and $s+1 is a power of 2
        ||die("1");                 # then print "1" and exit
    for($b=.5;$v>=$b*=2;)       # loop through the bits:
        $v&$b                       # if bit is set in $v
        &&~$s&$b                    # and not set in $s
            &&f($a,$s|$b);              # then set bit in $s and recurse
}
\$\endgroup\$
2
\$\begingroup\$

J, 49 bytes

g=.3 :'*+/*/"1+/"2((#y){.=i.{:$#:y)*"2#:(i.!#y)A.,y'

Do I need to count also the 'g=.'? I'm ready to add it.

A long explicit verb this time. I tried a tacit one for the same algorithm, but it turned out to be even longer and uglier than this. Far away from Adám's solution.

Explanation: (y is the right argument of the function)

                                             ,y - adds a leading axis to the argument 
                                             (if it's scalar becomes an array of length 1)
                                          .A    - finds the permutations according to the left argument
                                   (i.!#y)      - factorial of the length of the argument, for all permutations
                                 #:             - convert each element to binary
                             *"2                - multiply each cell by identity matrix
           (                )                   - group 
                   =i.{:$#:y                    - identity matrix with size the length
                                                  of the binary representation of the argument 
             (#y){.                             - takes as many rows from the identity matrix 
                                                  as the size of the list (pad with 0 if neded)
    */"1+/"2                                    - sums the rows and multiplies the items
                                                  to check if forms an identity matrix
 *+/                                            - add the results from all permutations and
                                                  returns 1 in equal or greater then 1

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Python 3, 126 120 bytes

Saved 6 bytes due to Mr. Xcoder

lambda x:g(x,max(map(len,map(bin,x)))-3)
g=lambda x,n:n<0 or any(g(x[:i]+x[i+1:],n-1)for i in range(len(x))if x[i]&2**n)

Try it online!

\$\endgroup\$
  • \$\begingroup\$ Could you add an ungolfed version? \$\endgroup\$ – Antti29 Nov 6 '17 at 12:48
  • \$\begingroup\$ [0]+[...] Is pointless isn't it? any(g(x[:i]+x[i+1:],n-1)for i in range(len(x))if x[i]&2**n) should suffice. \$\endgroup\$ – Mr. Xcoder Nov 6 '17 at 13:55
  • \$\begingroup\$ @Mr.Xcoder Yeah, I guess I was thinking about the max function when I added it \$\endgroup\$ – Halvard Hummel Nov 6 '17 at 16:03
1
\$\begingroup\$

Jelly, 17 bytes

BUz0Œ!ŒD€Ẏ
ṀBo1eÇ

A monadic link taking a list of numbers and returning 1 (truthy) or 0 (falsey).

Try it online!

This will time out on TIO for the longest of each of the test cases.

How?

BUz0Œ!ŒD€Ẏ - Link 1, possibilities (plus some shorter ones & duplicates): list of numbers
                                     e.g. [4, 5, 2]
B          - to binary list (vectorises)  [[1,0,0],[1,0,1],[1,0]]
 U         - upend                        [[0,0,1],[1,0,1],[0,1]]
   0       - literal zero                  0
  z        - transpose with filler        [[0,1,0],[0,0,1],[1,1,0]]
    Œ!     - all permutations             [[[0,1,0],[0,0,1],[1,1,0]],[[0,1,0],[1,1,0],[0,0,1]],[[0,0,1],[0,1,0],[1,1,0]],[[0,0,1],[1,1,0],[0,1,0]],[[1,1,0],[0,1,0],[0,0,1]],[[1,1,0],[0,0,1],[0,1,0]]]
      ŒD€  - diagonals of €ach            [[[0,0,0],[1,1],[0],[1],[0,1]],[[0,1,1],[1,0],[0],[0],[1,0]],[[0,1,0],[0,0],[1],[1],[0,1]],[[0,1,0],[0,0],[1],[0],[1,1]],[[1,1,1],[1,0],[0],[0],[0,0]],[[1,0,0],[1,1],[0],[0],[0,1]]]
         Ẏ - tighten                      [[0,0,0],[1,1],[0],[1],[0,1],[0,1,1],[1,0],[0],[0],[1,0],[0,1,0],[0,0],[1],[1],[0,1],[0,1,0],[0,0],[1],[0],[1,1],[1,1,1],[1,0],[0],[0],[0,0],[1,0,0],[1,1],[0],[0],[0,1]]

ṀBo1eÇ - Main link: list of numbers  e.g. [4, 5, 2]
Ṁ      - maximum                           5
 B     - to binary list                   [1,0,1]
   1   - literal one                       1
  o    - or (vectorises)                  [1,1,1]
     Ç - last link as a monad             [[0,0,0],[1,1],[0],[1],[0,1],[0,1,1],[1,0],[0],[0],[1,0],[0,1,0],[0,0],[1],[1],[0,1],[0,1,0],[0,0],[1],[0],[1,1],[1,1,1],[1,0],[0],[0],[0,0],[1,0,0],[1,1],[0],[0],[0,1]]
    e  - exists in?                        1    --------------------------------------------------------------------------------------------------------------^
\$\endgroup\$
1
\$\begingroup\$

R, 247 bytes 221 bytes

function(i){a=do.call(rbind,Map(`==`,Map(intToBits,i),1));n=max(unlist(apply(a,1,which)));any(unlist(g(a[,1:n,drop=F],n)))}
g=function(a,p){if(p==1)return(any(a[,1]));Map(function(x){g(a[x,,drop=F],p-1)},which(a[,p])*-1)}

Try it online!

Ungolfed version

f=function(i){                                   #anonymous function when golfed
  a=do.call(rbind,Map(`==`,Map(intToBits,i),1))  #convert integers to binary, then logical
                                                 #bind results together in matrix
  n=max(unlist(apply(a,1,which)))                #determine max number of bits
  any(unlist(g(a[,1:n,drop=F],n)))               #apply recursive function
}

g=function(a,p){
  if(p==1)return(any(a[,1]))                   #check if first bit is available still
  Map(function(x){g(a[x,,drop=F],p-1)},which(a[,p])*-1) #strip row used for current bit
                                                        #and apply the function recursively
}

I realized the no-row check was unnecessary with the drop=F arguments. Also removed some pesky whitespace.

\$\endgroup\$
1
\$\begingroup\$

PHP, 152 bytes

<?function b($a,$b,$s){$a[$s]=0;$r=$b-1;foreach($a as$i=>$v)if($v&1<<$b)$r=max(b($a,$b+1,$i),$r);return$r;}$g=$argv;$g[0]=0;echo!(max($g)>>b($g,0,0)+1);

Prints nothing for false, 1 for true.

Ungolfed:

<?

// Search an array for a value having a bit set at the given bit index.
// For each match, search for a next higher bit index excluding the current match.
// This way it "climbs up" bit by a bit, finally returning the highest bit index reached.
function bitSearch($valArr, $bitInd, $skipInd) {
    unset($valArr[$skipInd]);
    $result = $bitInd - 1;
    foreach ($valArr as $ind => $v) {
        if ($v & (1 << $bitInd)) {
            $result = max(bitSearch($valArr, $bitInd + 1, $ind), $result);
        }
    }
    return $result;
}

$argv[0] = 0;
$r = bitSearch($argv, 0, 0);
// Check if the highest bit index reached was highest in the largest value given.
if (max($argv) >> ($r + 1)) {
    echo("False\n");
} else {
    echo("True\n");
}
\$\endgroup\$
1
\$\begingroup\$

Jelly, 17 bytes

BUz0×J$€ŒpṢ=JPƲ€Ẹ

Test suite.

\$\endgroup\$
0
\$\begingroup\$

C , 79 bytes

b,i;main(a){for(;~scanf("%d",&a);i++)b|=a;puts("false\0true"+(b==(1<<i)-1)*6);}
\$\endgroup\$
  • \$\begingroup\$ Could you add an explanation? Also, a try it online link would be useful. \$\endgroup\$ – Antti29 Nov 9 '17 at 9:44
  • \$\begingroup\$ Some tips when golfing in C: 1/ in many challenges (this one included), you're allowed to submit a function instead of a full program, 2/ you have to output a truthy/falsey value, this can be anything as long as it's consistent (you can output 0 / 1 instead of "false"/"true"). Lastly, this code doesn't seem to work: [1, 7, 1] should return false, and [52, 114, 61, 19, 73, 54, 83, 29] should return true \$\endgroup\$ – scottinet Nov 9 '17 at 12:05
  • \$\begingroup\$ You're right, my bad \$\endgroup\$ – PrincePolka Nov 9 '17 at 15:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.