Le protocole d'urinoir

38

Contexte

Le soi-disant "protocole d'urinoir", décrivant l'ordre dans lequel les urinoirs individuels sont cueillis dans les toilettes d'un homme, a été discuté à plusieurs endroits. Une version est donnée dans cet article de blog xkcd . Cette question concerne une légère variation:

Arrangement : n urinoirs en ligne.
Protocole : chaque nouvelle personne sélectionne l’un des urinoirs les plus éloignés de ceux déjà utilisés.

Notez que cela n'impose aucune restriction quant à l'urinoir choisi par la première personne.

Mise à jour : La séquence du nombre de manières différentes par lesquelles n personnes peuvent sélectionner n urinoirs commence par 1, 2, 4, 8, 20 ... Notez que ce n'est pas la même chose que OEIS A095236 , qui décrit des restrictions légèrement plus strictes que celles-ci. question.

Tâche

Soit un entier n compris entre 0 et 10, affiche (dans n'importe quel ordre) tous les ordres possibles dans lesquels n personnes peuvent occuper n urinoirs. Chaque commande doit être imprimée comme arrangement final: une séquence de chiffres représentant les personnes (1-9 pour les 9 premières personnes, 0 pour la dixième), en partant de l’urinoir le plus à gauche, avec des séparateurs non alphanumériques optionnels entre (mais pas avant). ou après) les chiffres. Par exemple, les sorties suivantes sont toutes les deux valides:

>> 3
132
213
312
231

>> 4
1|3|4|2
1|4|3|2
3|1|4|2
4|1|3|2
2|3|1|4
2|4|1|3
2|3|4|1
2|4|3|1

Vous pouvez écrire un programme ou une fonction en prenant l’entrée via STDIN (ou l’alternative la plus proche), un argument de ligne de commande ou un argument de fonction. Les résultats doivent être imprimés sur STDOUT (ou l'alternative la plus proche).

Notation

Le code le plus court gagne. Les conditions générales s'appliquent.

Uri Granta
la source
1
Hm. Je reçois ceci pour 5 urinoirs . Il devrait être 16 lignes à la place. Quelqu'un voudrait-il préciser laquelle de ces solutions ne va pas? Ceci est en cours de mise en œuvre: Choisissez l’un des urinaux avec une distance maximale par rapport aux autres.
knedlsepp
1
Voilà pour Sandboxing :-( Spec est tel que décrit dans la tâche, pas dans la définition de la séquence. Je mettrai à jour dès que j'aurai accès à un ordinateur.
Uri Granta
1
@knedlsepp Les lignes 3, 4, 17 et 18 sont incorrectes. Dans ceux-ci, vous placez la personne n ° 3 dans une spanlongueur de 1, où il y a une spanlongueur de 2 disponible. J'ai soudainement réussi à m'embrouiller. Il semblerait que le PO soit intentionnellement dérivé du lien, et donc que le lien devrait être suivi?
BrainSteel
Spécification mise à jour pour noter que la tâche n’est pas identique à A095236.
Uri Granta
Est-il permis de sortir le format dans [1, 3, 2], où chacune de ces solutions est séparée par une nouvelle ligne? (donc pas seulement un séparateur de ",", mais aussi le début de "[" et la fin de "]")
orlp

Réponses:

11

Pyth, 53 51

MhSm^-dG2HjbmjdmehxkbQusmm+dkfqgTdeSmgbdQUQGUtQm]dQ

C'est une approche itérative. En considérant un ensemble possible d'emplacements partiellement remplis, nous trouvons tous les autres emplacements optimaux, puis générons la liste des emplacements correspondants et répétons l'opération.

Les résultats sont générés sous la forme [<first person's location>, <second person's location> ...], puis ils sont transformés au format souhaité. MhSm^-dG2Hdéfinit une fonction d'assistance qui recherche les distances minimales entre un décrochage donné et un décrochage occupé (au carré). Curieusement, le séparateur est libre.

Exemple exécuté.

Explication:

Tout d’abord, la fonction d’aide g, qui détermine la distance au carré minimale entre G et une valeur quelconque dans H.

MhSm^-dG2H
M             def g(G,H): return
 hS           min(                         )
   m     H        map(lambda d:        , H) 
    ^-dG2                      (d-G)**2

Ensuite, nous trouvons le maximum au-dessus des emplacements des urinoirs de la distance carrée minimale entre ce dernier et tout urinoir occupé:

( Qest l'entrée.)

eSmgbdQ
eS          max(                                   )
  m   Q         map(lambda b:      , range(len(Q)))
   gbd                       g(b,d)

dDans ce cas, il s’agit de la liste des urinoirs occupés, tandis bqu’itération sur les emplacements des urinoirs.

Ensuite, nous trouvons tous les emplacements d'urinoirs dont la distance minimale au carré de l'urinoir occupé le plus proche est égale à la valeur maximale trouvée ci-dessus.

fqgTdeSmgbdQUQ
f           UQ    filter(lambda T:                             , range(len(Q)))
 qgTd                             g(T,d) ==
     eSmgbdQ                                <value found above>

Ensuite, nous allons générer les listes d’emplacement d’urinoir créées en ajoutant les emplacements d’urinoir trouvés ci-dessus à d. Nous le ferons pour chaque liste précédente d’emplacement d’urinoirs, ce qui étendra les listes de longueur Nà N+1. Gest la liste des listes légales des emplacements des urinoirs occupés d’une longueur donnée.

smm+dkfqgTdeSmgbdQUQG
sm                  G    sum(map(lambda d:                               ,G)
  m+dk                                   map(lambda k:d+[k],            )
      fqgTdeSmgbdQUQ                                        <above list>

Ensuite, nous appliquerons l’expression ci-dessus à plusieurs reprises pour générer la liste complète des listes d’emplacements d’urinoirs occupés. u, la fonction de réduction fait exactement cela, autant de fois qu'il y a d'éléments dans son deuxième argument.

usmm+dkfqgTdeSmgbdQUQGUtQm]dQ
usmm+dkfqgTdeSmgbdQUQG           reduce(lambda G,H: <the above expression)
                      UtQ        repeat Q-1 times
                         m]dQ    starting with [[0], [1], ... [Q-1]]. 

Autre partir de la représentation ci - dessus, qui va [<1st location>, <2nd location>, ... ], à la forme de sortie souhaitée, [<person in slot 1>, <person in slot 2>, ... ]. Ensuite, le formulaire de sortie est joint à la chaîne de sortie et imprimé. L'impression est implicite.

jbmjdmehxkbQ
jbm             '\n'.join(map(λ k:                                    ,<above>)
   jdm     Q                      ' '.join(map(λ b:                ,Q)
        xkb                                        b.index(k)
      eh                                                     +1 %10
isaacg
la source
Bon sang, je devrais arrêter d'écrire des solutions récursives en Pyth. Je suis toujours battu: P
orlp
kajsdlkas^23asdjkla1lasdkj~JZasSSA- presque la moitié de la taille.
Optimiseur
@Optimizer J'ajouterai une explication lorsque je serai moins occupé.
isaacg
8

Pyth, 75 71 67

DcGHFk_UQJf!s:GeS,0-TkhS,h+TklGUQIJRsmcX>G0dhHhHJ)R]Gjbmjdmebkcm0Q0

Solution combinatoire récursive.

C'est une traduction assez directe de cette solution Python:

N = int(input())

def gen(l, p):
    for d in reversed(range(N)):
        s = []
        for i in range(N):
            if not sum(l[max(0,i-d):min(i+d+1, len(l))]):
                s.append(i)

        if s:
            r = []
            for possib in s:
                j = l[:]
                j[possib] = p+1
                r += gen(j, p+1)

            return r

    return [l]

print("\n".join(" ".join(str(x % 10) for x in sol) for sol in gen([0] * N, 0)))
orlp
la source
Comment ça marche? Plus en détail que "solution combinatoire récursive".
mardi
@tbodt Ajout du code Python que j'ai écrit avant de le traduire en Pyth.
Orlp
5

C, 929 878 octets

Celui-ci est un monstre, les gars. Désolé.

typedef unsigned long U;typedef unsigned char C;U f(int*u,n){C c[8],a[8];*(U*)(&c)=-1;int i,b=0,l=-9,s=-2,f=0,d;for (i=0; i<n; i++) {if (!u[i]&&s<0)s=i,l=0;if(!u[i])l++;if(u[i]&&s>=0){if(!s)l=2*l-1;d=(l-1)/2;if(b<d)*(U*)(a)=0,*(U*)(c)=-1,*c=s,*a=l,f=1,b=d;else if(b==d)c[f]=s,a[f++]=l;s=-1;}}if(s>=0&&l){l=2*l-1;d=(l-1)/2;if(b<d)*(U*)(c)=-1,*c=s,*a=l,f=1,b=d;else if(b==d)c[f]=s,a[f++]=l;}d=f;for(i=0;i<d;i++){if((c[i]+1)&&c[i]){if(c[i]+a[i]==n)c[i]=n-1;else{if(!(a[i]%2))c[f++]=b+c[i]+1;c[i]+=b;}}}return*(U*)c;}void P(int*u,n,i,c,m){for(i=0;i<n;i++){if(!u[i])c++;if(u[i]>m)m=u[i];}if(!c){for(i=0;i<n;i++)printf("%d",u[i]==10?0:u[i]);printf("\n");}else{int s[8][n];for(i=0;i<8;i++)for(c=0;c<n;c++)s[i][c]=u[c];U t=f(u,n);C*H=&t;for(i=0;i<8;i++)if((C)(H[i]+1))s[i][H[i]]=m+1,P(s[i],n,0,0,0);}}void L(n){int u[n],i,j;for(i=0;i<n;i++){for(j=0;j<n;j++)u[j]=j==i?1:0;P(u,n,0,0,0);}}

Définit 3 fonctions, f(int*,int) , P(int*,int,int,int,int)et L(int). Appelez L(n), et il sort à STDOUT.

Sortie pour n=5 :

14352
15342
31452
31542
41352
51342
41532
51432
24153
25143
34152
35142
23415
23514
24513
25413
24315
25314
24351
25341

Mise à jour: j'ai supprimé les séparateurs et corrigé le code. L’ancien code a non seulement échoué pour n = 7 +, mais n’a rien produit du tout pour n = 10 (oups!). J'ai plus soigneusement testé ce groupe. Il prend désormais en charge une entrée allant jusqu’à n = 13 (bien que le"%d" faille changer le pour "%x"qu’elle soit imprimée en hexadécimal). La taille de l'entrée dépend de sizeof(long)et on suppose que c'est 8en pratique.

Voici une explication de son fonctionnement et des raisons pour lesquelles une restriction aussi étrange existe:

Celles-ci ont été beaucoup utilisées, nous les définissons donc pour économiser quelques octets:

typedef unsigned long U; typedef unsigned char C;

Voici f :

U f(int*u,n){
    C c[8],a[8];
    *(U*)(&c)=-1;
    int i,b=0,l=-9,s=-2,f=0,d;
    for (i=0; i<n; i++) {
        if (!u[i]&&s<0)
            s=i,l=0;
        if(!u[i])
            l++;
        if(u[i]&&s>=0){
            if(!s)
                l=2*l-1;
            d=(l-1)/2;
            if(b<d)
                *(U*)(a)=0,
                *(U*)(c)=-1,
                *c=s,
                *a=l,
                f=1,
                b=d;
            else if(b==d)
                c[f]=s,a[f++]=l;
            s=-1;
        }
    }
    if(s>=0&&l){
        l=2*l-1;
        d=(l-1)/2;
        if(b<d)
            *(U*)(c)=-1,
            *c=s,
            *a=l,
            f=1,
            b=d;
        else if(b==d)
            c[f]=s,a[f++]=l;
    }
    d=f;
    for(i=0;i<d;i++){
        if((c[i]+1)&&c[i]){
            if(c[i]+a[i]==n)
                c[i]=n-1;
            else{
                if(!(a[i]%2))
                    c[f++]=b+c[i]+1;
                c[i]+=b;
            }
        }
    }
    return*(U*)c;
}

fprend un tableau d'entiers de taille n, et nlui - même. Le seul élément intelligent ici est qu'il renvoie un unsigned long, qui est converti en char[8]par la fonction appelante. Chaque caractère du tableau est ainsi défini sur 0xFFou sur un index pointant vers un urinal valide pour la personne suivante. En effet n<10, nous n’avons jamais besoin de plus de 5 octets pour contenir tous les urinoirs valides que la personne suivante peut utiliser.

VoiciP :

void P(int*u,n,i,c,m){
    for(i=0;i<n;i++){
        if(!u[i])c++;
        if(u[i]>m)m=u[i];
    }
    if(!c){
        for(i=0;i<n;i++)
            printf("%d",u[i]==10?0:u[i]);
        printf("\n");
    }
    else{
        int s[8][n];
        for(i=0;i<8;i++)
            for(c=0;c<n;c++)
                s[i][c]=u[c];
        U t=f(u,n);
        C*H=&t;
        for(i=0;i<8;i++)
            if((C)(H[i]+1))
                s[i][H[i]]=m+1,P(s[i],n,0,0,0);
    }
}

Pprend un tableau ude taille ndans lequel exactement un élément est défini sur 1et les autres sont 0. Il trouve ensuite et imprime toutes les permutations possibles de manière récursive.

VoiciL :

void L(n){
    int u[n],i,j;
    for(i=0;i<n;i++){
        for(j=0;j<n;j++)
            u[j]=j==i?1:0;
        P(u,n,0,0,0);
    }
}

Lappelle simplement des P ntemps avec des positions de départ différentes à chaque fois.

Pour les intéressés, cela (moins jouéf au golf ) générera la séquence dans A095236 .

U f(int*u,n) {
    C c[8];
    *(U*)(&c) = -1;
    int i,b=0,l=-10,s=-2,f=0,d;
    for (i=0; i<n; i++) {
        if (!u[i]&&s<0) {
            s=i,l=0;
        }
        if(!u[i]){
            l++;
        }
        if (u[i]&&s>=0) {
            if (!s) {
                l=2*l-1;
            }
            if (b<l) {
                *(U*)(&c)=-1;
                c[0]=s;
                f=1;
                b=l;
            }
            else if (b==l)
                c[f++]=s;
            s=-1;
        }
    }
    if (s>=0&&l) {
        l=2*l-1;
        if (b<l) {
            *(U*)(&c)=-1;
            c[0]=s;
            f=1;
            b=l;
        }
        else if (b==l)
            c[f++]=s;
    }
    d=f;
    for (i=0; i<d; i++) {
        if ((c[i]+1)&&c[i]) {
            if (c[i]+b==n) {
                c[i]=n-1;
            }
            else{
                if (!(b%2)) {
                    c[f++]=(b-1)/2+c[i]+1;
                }
                c[i]+=(b-1)/2;
            }
        }
    }
    return *(U*)c;
}
BrainSteel
la source
"1 4 ..." au début semble être contre la spécification: si le premier nombre est 1, le prochain doit être 5.
anatolyg
2
@anatolyg No. Voici une explication détaillée de la manière dont "1 4" peut se produire: gist.github.com/orlp/a5706ba664b70209b48a
orlp
N'oubliez pas que les séparateurs sont facultatifs. Vous pouvez économiser 1 octet (!) En supprimant l'espace après le% d :-)
Uri Granta
@ UriZarfaty Merci! En fait, il y a une tonne d'octets à sauvegarder ici. J'écris actuellement une meilleure solution et une explication.
BrainSteel
@yo 'Je pense que vous confondez un peu la sortie. Une sortie de 14352signifie que la personne n ° 1 a choisi l'urinal le plus à gauche. La personne n ° 2 a choisi la personne la plus à droite, qui a ensuite forcé la n ° 3 au milieu. Ce n'est pas le numéro de l'urinal choisi ensuite qui doit être fourni.
BrainSteel
4

Python 2, 208

n=input()
r=range(n)
l=[0]*n
def f(a,d=-1):
 if a>n:print''.join(l);return
 for i in r:
  t=min([n]+[abs(i-j)for j in r if l[j]])
  if t==d:p+=[i]
  if t>d:p=[i];d=t
 for i in p:l[i]=`a%10`;f(a+1);l[i]=0
f(1)

Approche récursive.

Jakube
la source
4

JavaScript (ES6) 153 160 169

modifier Utilisez Math.min pour trouver (bien sûr) la distance maximale: code simplifié et 16 octets enregistrés.

La recherche récursive peut fonctionner avec n> 10, il suffit de supprimer% 10 (et d’être prêt à attendre pendant que la console déroule toute sa sortie).

J'utilise un seul tableau pour stocker l'emplacement en cours d' utilisation (nombres positifs) ou la distance courante de la fente la plus proche (numéros de négatif , de sorte <et >sont permutés dans le code).

F=n=>{(R=(m,d,t,x=Math.min(...d=m?
  d.map((v,i)=>(c=i<t?i-t:t-i)?v<c?c:v:m%10)
  :Array(n).fill(-n)))=>
x<0?d.map((v,i)=>v>x||R(-~m,d,i)):console.log(d+[]))()}

Ungolfed

F=n=>{
  var R=(m, // current 'man', undefined at first step
   d, // slot array
   t // current position to fill
  ) =>
  {
    if (m) // if not at first step
    {
      d[t] = m % 10; // mark slot in use, (10 stored as 0 )
      d = d.map((v,i) => { // update distances in d[] 
        var c = i<t ? i-t : t-i; // distance from the current position (negated)
        return v < c ? c : v; // change if less than current distance
      });
    }
    else
    {
      d = Array(n).fill(-n) // fill distance array with max at first step
      // negative means slot free, value is the distance from nearest used slot
      // >= 0 means slot in use by man number 1..n 
    }
    var x = Math.min(...d);
    if ( x < 0 ) // if there is still any free slot
    {
      d.forEach((v,i) => { // check distance for each slot 
        if (v <= x) // if slot is at max distance, call recursive search
          R(-~m, [...d], i) // ~- is like '+1', but works on undefined too
      });
    }
    else
    {
      console.log(d+[]); // no free slot, output current solution
    }
  }

  R() // first step call
}

Testez dans la console Firefox / FireBug

F(5)

1,4,3,5,2
1,5,3,4,2
3,1,4,5,2
3,1,5,4,2
4,1,3,5,2
5,1,3 , 4,2
4,1,5,3,2
5,1,4,3,2
2,4,1,5,3
2,5,1,4,3
3,4,1,5,2
3 , 5,1,4,2
2,3,4,1,5
2,3,5,1,4
2,4,3,1,5
2,5,3,1,4
2,4,5, 1,3
2,5,4,1,3
2,4,3,5,1
2,5,3,4,1

edc65
la source
2

Mathematica, 123 104

f[n_,s_:{}]:=If[Length@s<n,f[n,s~Join~{#}]&/@MaximalBy[Range@n,Min@Abs[#-s]&];,Print@@Ordering@s~Mod~10]
Alephalpha
la source
@ MartinBüttner n~f~s~Join~{#}deviendra Join[f[n,s],{#}].
Alephalpha
Oh oui, j'ai pensé que c'était juste associatif.
Martin Ender
1

MATLAB, 164

function o=t(n),o=mod(r(zeros(1,n)),10);function o=r(s),o=[];d=bwdist(s);m=max(d);J=find(d==m);if~d,o=s;J=[];end,n=max(s)+1;for j=J,o=[o;r(s+n*(1:numel(s)==j))];end
Knedlsepp
la source
1

Perl, 174

Pas très court, mais amusant. Je ne compte pas use feature 'say';dans le total d'octets.

$n=pop;@u="_"x$n." "x$n."_"x$n;for$p(1..$n){@u=map{my@r;for$x(reverse 0..$n){
s/(?<=\D{$x}) (?=\D{$x})/push@r,$_;substr $r[-1],pos,1,$p%10/eg and last;
}@r}@u}y/_//d&&say for@u

De-golfé:

$n = pop; # Get number of urinals from commandline
@state = ( "_" x $n . " " x $n . "_" x $n );

for my $person (1 .. $n) {
  # Replace each state with its list of possible next states.
  @state = map {
    my @results;
    for my $distance (reverse 0 .. $n) {
      # If there are any spots with at least $distance empty on
      # both sides, then add an entry to @results with the current
      # $person number in that spot, for each spot. Note that this
      # is only used for its side-effect on @results; the modified $_
      # is never used.
      s{
        (?<=\D{$distance})
        [ ]
        (?=\D{$distance})
      }{
        push @results, $_;
        substr $results[-1], pos(), 1, $person % 10;
      }xeg
      # If we found any spots, move on, otherwise try
      # with $distance one lower.
      and last;
    }
    # New state is the array we built up.
    @results;
  } @state;
}

# After adding all the people, remove underscores and print the results
for my $result (@state) {
  $result =~ tr/_//d;
  say $result;
}
Hobbs
la source
1

C, 248 octets

Ce code utilise un algorithme récursif pour générer le résultat souhaité.

void q(char*f,int l,int d,char*o){char*c=f;while(f<c+l){if(!*f){sprintf(o+4*d,"%03i,",f-c);*f=1;q(c,l,d+1,o);*f=0;}f++;}if(d+1==l){o[4*d+3]=0;printf("%s\n",o);}}int main(int i,char**v){int k=atoi(v[1]);char*c=calloc(k,5),*o=c+k;q(c,k,0,o);free(c);}

Étendu:

void printperms(char* memory,int length,int offset,char*output)
{
    char*temp_char=memory;
    while(memory<temp_char+length)
    {
        if(!*memory)
        {
            sprintf(output+4*offset,"%03i,",memory-temp_char);
            *memory=1;
            printperms(temp_char,length,offset+1,output);
            *memory=0;
        }
        memory++;
    }
    if(offset+1==length)
    {
        output[4*offset+3]=0;
        printf("%s\n",output);
    }
}

int main(int i,char**v)
{
    int argument=atoi(v[1]);
    char*t=calloc(argument,5),*output=t+argument;
    printperms(t,argument,0,output);
    free(t);
}
Gerwin
la source
1

Bash, 744 674 octets

C'est encore trop long :). J'utilise une chaîne pour représenter la rangée d'urinoirs et un algorithme d'inondation pour rechercher les urinoirs les plus distants dans chaque phase de la récursion. Le code non-ludique est presque explicite. Le nombre d'urinoirs est lu à partir du clavier.

Code (golfé):

read l;u=----------;u=-${u::$l}-
s(){ u=${u:0:$1}$2${u:$((1+$1))};}
m(){ local u=$1;a=();while :;do [ 0 -ne `expr index - ${u:1:$l}` ]||break;t=$u;y=$u;for i in `seq $l`;do [ ${y:$i:1} = - ]||{ s $(($i-1)) X;s $(($i+1)) X;};done;done;while :;do k=`expr index $t -`;[ 0 != $k ]||break;t=${t:0:$(($k-1))}X${t:$k};if [ 1 -ne $k ]&&[ $(($l+2)) -ne $k ];then a+=($(($k-1)));fi;done;}
e(){ local u f b v;u=$1;f=$2;if [ 1 -eq $l ];then echo 1;return;fi;if [ 1 = $f ];then for i in `seq $l`;do v=$u;s $i 1;e $u 2;u=$v;done;else m $u;b=(${a[@]});if [ 0 -eq ${#b} ];then echo ${u:1:$l};else for i in ${b[@]};do v=$u;s $i $(($f%10));e $u $(($f+1));u=$v;a=(${b[@]});done;fi;fi;}
e $u 1

Utilisation:

$ source ./script.sh
input number of urinals from keyboard

Et ungolfed ça va:

read l  # read number of urinals
u=----------
u=-${u:0:$l}- #row is two positions longer (it will be helpful when finding the most distant urinals)

# So, for the end, with 6 men, u might look like this:
# -143652-

# subu no fellow_no => set urinal [number] occupied by [fellow_no]
# this is just convenience for resetting a character inside a string
subu(){ u=${u:0:$1}$2${u:$((1+$1))};}


# this will be iterated in longest to find the remotest places:
# -1---3---2- => spreadstep => X1X-X3X-X2X => spreadstep => X1XXX3XXX2X
# see longest() to get more explanation.
spreadstep()
{
    y=$u
    for i in `seq 1 $l`
    do
    if [ "${y:$i:1}" != "-" ]
    then
        subu $(($i-1)) X
        subu $(($i+1)) X
    fi
    done
}

# Find the urinals with the longest distance. It uses spreadstep() - see above.
# -1---3---2- => spreadstep => X1X-X3X-X2X => spreadstep => X1XXX3XXX2X
# ---> last state with free ones was X1X-X3X-X2X ,
#                                     123456789
# free urinals are no. 3 and no. 7 => save them to arr
longest()
{
    local u=$1
    arr=()
    while true
    do
        if [ 0 -eq `expr index - ${u:1:$l}` ]
        then
            break
        fi
        save=$u
        spreadstep
    done

    while true
    do
        index=`expr index $save -`
        if [ 0 == $index ]
        then
            break
        fi

        save=${save:0:$(($index-1))}X${save:$index}
        if [ 1 -ne $index ] && [ $(($l+2)) -ne $index ]
        then
            arr+=($(($index-1)))
        fi
    done
}

# main function, recursively called
# the first fellow may take any of the urinals.
# the next fellows - only those with the longest distance.
placements_with_start()
{
    local u=$1
    local fellow=$2
    if [ 1 -eq $l ] # special case - there is no 2nd fellow, so below code would work incorrect 
    then
        echo "1"
        return
    fi
    if [ 1 == $fellow ]       # may take any of urinals
    then
        for i in `seq 1 $l`
        do
            local _u=$u
            subu $i 1                     # take the urinal
            placements_with_start $u 2    # let the 2nd fellow choose :)
            u=$_u
        done
    else
        longest $u   # find the ones he can take
        local _arr=(${arr[@]})
        if [ 0 -eq ${#_arr} ]
        then
            echo ${u:1:$l}    # no more free urinals - everyone took one - print the result
        else
            for i in ${_arr[@]}
            do
                local _u=$u
                subu $i $(($fellow % 10))                # take urinal
                placements_with_start $u $(($fellow+1))  # find locations for for next fellow
                u=$_u
                arr=(${_arr[@]})
            done
        fi
    fi
}

placements_with_start $u 1
pawel.boczarski
la source