Color me a Pole

22

1

Lets say your job is to paint poles, and a client asks you to paint a pole with 4 red sections and 3 yellow sections. You can do that pretty easily as follows:

r y r y r y r

With just yellow and red stripes. Now lets say your client asks you to paint a pole with 2 red sections, 2 yellow sections, and 1 green section. There are a couple of ways you could paint your pole

g y r y r
y g r y r
y r g y r
y r y g r
y r y r g
g r y r y
r g y r y
r y g r y
r y r g y
r y r y g
y r g r y
r y g y r

More precisely thats 12 ways to paint the pole. This blows up the more colors and sections that are involved

Now if your client says they want 3 red sections and 1 yellow section there is no way to paint a pole like that. Because no matter how you attempt to arrange the sections two red sections will touch, and when two red sections touch they become a single red section.

And that is pretty much our one rule for painting poles

Adjacent sections may not be of the same color

Task

Given a list of colors and sections required, output the number of possible ways to paint a pole as requested. You may represent colors in any reasonable way (integers, characters, strings), but you will never be given more than 255 different colors at a time. If you wish you can even choose to not have the colors assigned names and just take a list of section counts if that is easier.

Test Cases

These are rather hard to calculate by hand, especially as they get larger. If anyone has a suggested test case I'll add it.

[4,3]    -> 1
[2,2,1]  -> 12
[3,1]    -> 0
[8,3,2]  -> 0
[2,2,1,1]-> 84

Post Rock Garf Hunter

Posted 2017-07-11T14:32:54.473

Reputation: 55 382

May we take input as, for example, "rrrryyy" for [4,3]? – Leo – 2017-07-11T14:41:51.787

@Leo Sure that is perfectly reasonable. – Post Rock Garf Hunter – 2017-07-11T14:42:47.810

Can I get input as [1, 1, 1, 1, 2, 2, 2]? I suppose so. – Erik the Outgolfer – 2017-07-11T14:49:33.260

@EriktheOutgolfer Yes that is also a reasonable input method – Post Rock Garf Hunter – 2017-07-11T14:50:00.077

If you take in a list of colors, may you assume it to be sorted? – xnor – 2017-07-11T19:21:58.030

@xnor Yes you may, – Post Rock Garf Hunter – 2017-07-11T19:28:41.600

1

Turns out the closed form solution is pretty damn hard for even professional mathematicians...

– Akshat Mahajan – 2017-07-12T05:52:32.017

4Not super important, but capitalizing the word Pole makes it sounds like you are talking about a person from Poland. – NH. – 2017-07-12T15:57:45.770

Answers

9

Mathematica, 37 44 48 60 62 bytes

Take input as a list of integers {1, 1, 1, 2, 2}. Try it on Wolfram Sandbox.

Pattern-matching method, thanks @Not a tree !

Count[Split/@Permutations@#,{{_}..}]&

Split splits a single list into sublists of consecutive elements, e.g. {1, 1, 2, 3, 4, 4} into {{1, 1}, {2}, {3}, {4, 4}}

{{_}..} is, namely, {{_}, {_}, {_}, ...}. The pattern matches a list of unary sublists.

Differences method, 48 bytes:

Tr@Abs@Clip[1##&@@@Differences/@Permutations@#]&

The code uses Differences to determine whether adjacent elements are the same.

Step by step:

  1. Permutations@# generates all permutations of input list to a N!*N list.
  2. Differences/@ calculates the difference between N elements, and yields a N!*(N-1) list.
  3. 1##&@@@ calculates the multiplication of all lists. If a list contains 0 (two adjacent elements are the same), the result will be 0, otherwise non-zero, to a N! list.
  4. Clip[] acts like Sign[], transform the list from (-inf, inf) to [-1, 1]
  5. Tr@Abs turns all -1 into 1 and now the N!-length list contains only 0 (invalid) and 1 (valid). So we just sum the list.

Keyu Gan

Posted 2017-07-11T14:32:54.473

Reputation: 2 028

4You can save 4 bytes with some pattern matching: Permutations@#~Count~Except@{___,x_,x_,___}&. – Not a tree – 2017-07-11T16:25:50.543

2I have another one: Count[Split/@Permutations@#,{{_}..}]&, 37 bytes! – Not a tree – 2017-07-12T11:05:14.857

7

Jelly, 7 bytes

Œ!QIẠ€S

Try it online!

Takes input as e.g. [1,1,1,1,2,2,2] for [4,3]. The [8,3,2] testcase takes too long to run on TIO.

How it Works

Œ!QIẠ€S - main link, input as a list
Œ!      - all permutations
  Q     - remove duplicates
   I    - take increments (returns a 0 for two adjacent identical numbers)
    Ạ€  - apply “all” atom to each: 0 for containing 0 and 1 otherwise
      S - sum

fireflame241

Posted 2017-07-11T14:32:54.473

Reputation: 7 021

You abused grace period...;) – Erik the Outgolfer – 2017-07-11T15:03:09.967

Does Œ!QIẠ€S work? Try it online!

– nmjcman101 – 2017-07-11T15:07:13.390

@nmjcman101 That appears to work. Nice find! I preferred the P over the any and all atom for its simplicity. – fireflame241 – 2017-07-11T15:10:08.180

@fireflame241 Technically that's not the any-and-all atom, it's the all atom. – Erik the Outgolfer – 2017-07-11T15:16:17.117

BTW P€ instead of Ạ€ would still work. – Erik the Outgolfer – 2017-07-11T15:20:35.113

@EriktheOutgolfer No. Since they are summed, using P would count [3,1,2] negative 2 times. – fireflame241 – 2017-07-11T15:22:32.060

@fireflame241 Oh right I was confusing with my 05AB1E answer. – Erik the Outgolfer – 2017-07-11T15:23:13.287

5

05AB1E, 7 bytes

œÙ€¥PĀO

Try it online!

-1 thanks to nmjcman101 on another answer.

Erik the Outgolfer

Posted 2017-07-11T14:32:54.473

Reputation: 38 134

5

Mathematica, 50 bytes

Expand[1##&@@(LaguerreL[#,-1,x](-1)^#)]/._^i_:>i!&

Try it in Mathics, or at the Wolfram sandbox!

Takes input like in the test cases — e.g. {4,3} means "4 red stripes, 3 yellow stripes".

This is a naïve implementation of a formula I found here. "Naïve" means "I have no idea how the maths works so please don't ask me for an explanation…"

Not a tree

Posted 2017-07-11T14:32:54.473

Reputation: 3 106

1Can we have an explanation of the maths given in this answer? – TheLethalCoder – 2017-07-11T16:21:20.623

@TheLethalCoder Seconded, can someone please explain the maths to me? – Not a tree – 2017-07-11T16:27:41.167

5

Python 3.5, 65 bytes

f=lambda s,p=0:sum(f(s.replace(c,'',1),c)for c in{*s}-{p})or''==s

Try it online!

xnor

Posted 2017-07-11T14:32:54.473

Reputation: 115 687

3

Ruby 2.4, 47 bytes

Input is a list of characters: For the test case [4,3], input can be %w[a a a a b b b], "1111222".chars, or some other array formatting method that's valid in Ruby.

->x{x.permutation.uniq.count{|a|a*''!~/(.)\1/}}

Requires 2.4 for Enumerator#uniq (earlier versions only had it available on the Array class). As such, the TIO link adds 5 bytes to convert the permutation enumerator to an array first via to_a, since it does not have the above function.

Try it online!

Value Ink

Posted 2017-07-11T14:32:54.473

Reputation: 10 608

3

R, 72 bytes

pryr::f(sum(sapply(unique(combinat::permn(x)),pryr::f(!sum(!diff(x))))))

Creates the function

function (x) 
{
    sum(sapply(unique(combinat::permn(x)), pryr::f(!sum(!diff(x)))))
}

Takes input in the form [1,1,1,1,2,2,2] as per Erik the Outgolfer's comment. Uses combinat's permn function to create a list of all permutations, and then unique to get all distinct entries. sapply then applies the following function on all entries:

pryr::f(!sum(!diff(x)))

Which evaluates to

function (x) 
!sum(!diff(x))

Note that this x is not the same as the x in the big function's input. Using another character in this function would fool pryr::f into believing the big function needs another argument.

Anyways, when given a permutation, this function takes the difference between the vector: 2 1 3 4 2 1 -> -1 2 1 -2 -1. ! converts nonzero's into FALSE and zeros into TRUE, so the vector becomes FALSE FALSE FALSE FALSE FALSE. Summing that to check if there are any TRUEs (TRUE would imply diff=0 --> two the same consecutive numbers). We can again invert this with ! to get a boolean on whether or not there are consecutive values in the permutation.

Summing over these booleans gives us the total number of permutations where this is not the case.

Doesn't work for the [8,3,2] testcase because it requires a vector of 46GB to store those permutations.

JAD

Posted 2017-07-11T14:32:54.473

Reputation: 2 898

2

Jelly, 11 bytes

Œ!Q⁻2\Ạ$ÐfL

Try it online!

Erik the Outgolfer

Posted 2017-07-11T14:32:54.473

Reputation: 38 134

2

Python 2, 140 89 bytes

Input format is 'aaaabbb' for test case [4,3].

lambda s:len({p for p in permutations(s)if all(map(cmp,p,p[1:]))})
from itertools import*

Try it online!

Felipe Nardi Batista

Posted 2017-07-11T14:32:54.473

Reputation: 2 345

2

Ruby, 84 76 bytes

f=->a,x=p{i=s=0;a.map{a[i-=1]-=1;a[i]<0||i!=x&&s+=f[a,i];a[i]+=1}.max>0?s:1}

A recursive lambda function. Looks at each possible color and dose a recursive tree search, counting the number of times it uses all stripes.

Explanation (for old version):

f=->
  a, # a is the input array in [3,3,4] form
  x = -1 # x is the last color placed (-1 when run normaly, used in recursive calls)
{
  j = i = s = 0;
  # i is the index
  # s is the sum of valid final patterns (the answer)
  # j is used to count the total stripes

  a.map{|e| # Iterate over array of colors

    a[i] -= 1; # remove a stripe of current color (the array will be used in recursive call)

    s += f[a,i] if i!=x && e>0;
      # add to sum recursively if:
        # we are not using the same color as the last color AND
        # we have stripes of the current color left to paint

    a[i] += 1; # replace the stripe we removed above 

    j += a[i]; # add stripes to j

    i+=1 # increment the index

  }; # End loop

  j == 0 ? 1 : s
  # if we had stripes, give the recursive sum, otherwise return 1 
}

MegaTom

Posted 2017-07-11T14:32:54.473

Reputation: 3 787

x=p as the initial condition? p acts as an alias of nil in this case and should satisfy the check it's being used for. – Value Ink – 2017-07-12T04:22:49.707

2

Husk, 8 bytes

#ȯ¬ṁtguP

Try it online! Takes input in the format "aaabb" for [3,2]. Times out on the longest test case.

Explanation

Nothing fancy here, just counting the unique permutations where all groups of adjacent elements have length 1.

#ȯ¬ṁtguP
       P  Permutations.
      u   Remove duplicates.
#ȯ        Count how many satisfy the following condition:
     g    group adjacent elements,
   ṁt     concatenate tails of groups
  ¬       and negate.

Zgarb

Posted 2017-07-11T14:32:54.473

Reputation: 39 083

1

MATL, 11 8 bytes

Y@Xu!dAs

Input format is [1 1 1 1 2 2 2] for [4 3], etc.

Runs out of memory for the last test case.

Try it online!

Explanation

Y@    % Implicit input. Matrix of all permutations. Each row is a permutation
Xu    % Unique rows
!     % Transpose
d     % Consecutive differences along each column
A     % All: true for columns such that all its entries are nonzero
s     % Sum. Implicitly display

Luis Mendo

Posted 2017-07-11T14:32:54.473

Reputation: 87 464