Pisuar Protokolü


38

Arka fon

Bireysel pisuarların bir erkek banyosunda toplanma sırasını açıklayan "Pisuvar Protokolü" adı verilen birçok yerde tartışılmıştır. Bu xkcd blog gönderisinde bir sürüm verilmiştir . Bu soru hafif bir değişiklikle ilgilidir:

Düzenleme : Bir sıradaki pisuarlar.
Protokol : her yeni kişi, kullanımda olanlardan en uzak pisuarlardan birini seçer.

Bunun , ilk kişi tarafından pisuarın toplanmasına hiçbir kısıtlama getirmediğini unutmayın .

Güncelleme : Hangi n kişilerde seçmek n pisuar başlar ile farklı şekillerde sayısının dizisi 1, 2, 4, 8, 20 ... Not bu değil aynı şekilde OEIS A095236 bu biraz daha sıkı kısıtlamalar açıklar, soru.

Görev

0 ile 10 arasında bir tamsayı verildiğinde, n insanların pisuarları işgal edebileceği tüm olası siparişleri (herhangi bir sırayla) verir. Her siparişte son düzenleme olarak basılmalıdır: halkı temsil eden bir dizi basamak (ilk 9 kişi için 1-9, onuncu için 0), en sol pisuardan başlayarak, aralarında isteğe bağlı alfanümerik olmayan ayırıcılar (ancak önce değil) veya sonra) haneler. Örneğin, aşağıdaki çıktıların her ikisi de geçerlidir:

>> 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

STDIN (veya en yakın alternatif), komut satırı argümanı veya işlev argümanı üzerinden girdi alarak bir program veya işlev yazabilirsiniz. Sonuçlar STDOUT'a (veya en yakın alternatife) yazdırılmalıdır.

puanlama

En kısa kod kazanır. Standart şartlar ve koşullar geçerlidir.


1
Hm. 5 pisuar için alıyorum bu . Bunun yerine 16 satır olmalıdır. Birisi lütfen bu çözümlerden hangisinin yanlış olduğunu detaylandırabilir mi? Bu şu anda uygulanmaktadır: Pisuvarlardan herhangi birini başka birine maksimum mesafeyle seçin.
knedlsepp

1
. Öyle ki korumalı alan :-( Spec görev açıklanan olduğunca değil, sekans tanım Ben en kısa bilgisayara olsun güncelleyeceğiz.
Uri Granta

1
@ knedlsepp Satır 3, 4, 17, 18 hatalı. Bunlarda # 3 kişiyi span, 1 spanboyunda, 2 boyunun olduğu bir yere yerleştirirsiniz . Birdenbire kendimi karıştırmayı başardım. OP'nin kasıtlı olarak linkten türetildiği anlaşılıyor ve bu nedenle link izlenmeli mi?
BrainSteel

Görevin A095236 ile aynı olmadığını unutmayın .
Uri Granta

Formatın [1, 3, 2] biçiminde çıkmasına izin veriliyor mu? Bu tür çözümlerin her biri yeni satırlarla ayrılıyor mu? (bu yüzden sadece "," bir seperatör değil, aynı zamanda "[" nin başlangıcı ve "]" sonu)
orlp

Yanıtlar:


11

Pyth, 53 51

MhSm^-dG2HjbmjdmehxkbQusmm+dkfqgTdeSmgbdQUQGUtQm]dQ

Bu yinelemeli bir yaklaşımdır. Sıralı konum gruplarına kısmen doldurulmuş bir olası göz önüne alındığında, tüm uygun olan diğer yerleri buluruz, daha sonra ilgili konum listesini oluşturur ve tekrarlarız.

Sonuçlar formda üretilir [<first person's location>, <second person's location> ...], daha sonra bu istenen formata dönüştürülür. MhSm^-dG2HBelirli bir duraktan işgal edilmiş bir duraka (kare) kadar minimum mesafeleri bulan bir yardımcı fonksiyon tanımlar. Eğlenceli, ayırıcı serbesttir.

Örnek çalışma

Açıklama:

İlk olarak, gG ile H arasındaki herhangi bir değer arasındaki minimum kare mesafeyi bulan yardımcı fonksiyon .

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

Daha sonra, bu pisuar ile işgal edilmiş pisuar arasındaki minimum kare mesafenin pisuar üstündeki maksimum yerlerini bulduk:

( Qgiriş.)

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

dBu durumda, işgal edilmiş pisuarların listesi, bpisuar yerleri üzerinde tekrarlanır.

Daha sonra, en yakın işgal edilen pisuvardan minimum kare uzaklığı yukarıda bulunan maksimum değere eşit olan tüm pisuar yerlerini tespit ediyoruz.

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

Daha sonra, yukarıda bulunan pisuar yerlerini ekleyerek oluşturulan pisuar yer listelerini oluşturacağız d. Biz böylece uzunluğu listelerini uzanan, pisuar konumların her önceki liste için yapacağız Niçin N+1. GBelirli bir uzunlukta işgal edilmiş pisuar yerlerinin yasal listelerinin listesidir.

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

Daha sonra, işgal edilmiş pisuar lokasyonlarının tam listesini oluşturmak için yukarıdaki ifadeyi tekrar tekrar uygulayacağız. uindirgeme işlevi, tam olarak bunu yapar, ikinci argümanındaki elemanlar kadar.

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]]. 

[<1st location>, <2nd location>, ... ]İstediğiniz çıktı şekline giden yukarıdaki göstergeden dönüştürün [<person in slot 1>, <person in slot 2>, ... ]. Ardından, çıktı formu çıktı dizisine birleştirilir ve yazdırılır. Baskı çok açık.

jbmjdmehxkbQ
jbm             '\n'.join(map(λ k:                                    ,<above>)
   jdm     Q                      ' '.join(map(λ b:                ,Q)
        xkb                                        b.index(k)
      eh                                                     +1 %10

Kahretsin, Pyth'te özyinelemeli çözümler yazmayı bırakmalıyım. Her zaman
dövüşürüm

kajsdlkas^23asdjkla1lasdkj~JZasSSA- neredeyse yarısı kadar.
Doktor

@Optimizer Daha az meşgul olduğumda bir açıklama ekleyeceğim.
isaacg

8

Pyth, 75 71 67

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

Özyinelemeli kombinasyonel çözüm.

Bu Python çözümünden oldukça doğrudan bir çeviri.

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)))

Bu nasıl çalışıyor? "Özyinelemeli kombinasyonel çözüm" den daha ayrıntılı olarak.
tbodt

@tbodt Pyth'a çevirmeden önce yazdığım Python kodunu ekledi.
or Marp

5

C, 929 878 bayt

Bu bir canavar, millet. Üzgünüm.

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);}}

Tanımlar 3 fonksiyonlar, f(int*,int), P(int*,int,int,int,int), ve L(int). Call L(n)ve STDOUT'a çıkar.

İçin çıktı n=5:

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

Güncelleme: Ayırıcıları kaldırdım ve kodu düzelttim. Eski kod sadece n = 7 + için değil aynı zamanda n = 10 (oops!) İçin hiçbir şey çıkmadı. Bu grubu daha ayrıntılı olarak test ettim. Şimdi n = 13'e kadar girişi destekliyor ( onaltılık olarak basılacak "%d"şekilde değiştirilmesi gerekiyor "%x"). Girişin büyüklüğü bağlıdır sizeof(long)ve 8pratikte olduğu varsayılmaktadır .

İşte nasıl çalıştığını ve neden bu kadar garip bir kısıtlamanın var olduğunun bir açıklaması:

Bunlar çok kullanıldı, bu yüzden birkaç bayt kurtarmaları için onları tanımladık:

typedef unsigned long U; typedef unsigned char C;

İşte 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;
}

fbir boyut tamsayı dizisi nve nkendisi alır. Buradaki tek akıllı bit, onu çağıran işlev tarafından unsigned longdönüştürülen bir a döndürür char[8]. Bu nedenle dizideki her karakter 0xFF, sonraki kişi için geçerli bir pisuar işaret eden bir dizine ya da dizine ayarlanır . Zira bir n<10sonraki kişinin kullanabileceği her pisuarın üstünü tutmak için asla 5 bayttan daha fazlasına ihtiyacımız yok.

İşte P:

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);
    }
}

Ptam olarak bir elemanın ayarlandığı ve diğerlerinin ayarlandığı bir uboyut dizisi alır . Daha sonra tekrar tekrar mümkün olan her permütasyonu bulur ve yazdırır.n10

İşte L:

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);
    }
}

Lsadece P nher seferinde farklı başlangıç ​​konumlarına sahip zamanları çağırır .

İlgilenenler için, bu (daha az golf) A095236'daki fdiziyi üretecektir .

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;
}

"1 4 ..." başlangıçta belirtime aykırı görünüyor: ilk sayı 1 ise, bir sonraki 5 olmalı.
anatolyg 18:15

2
@anatolyg Hayır. Burada "1 4" ün
or Marp '21

Unutmayın, ayırıcılar isteğe bağlıdır. % D :-) sonra boşluğu kaldırarak 1 bayt (!)
Kazanabilirsiniz

@UriZarfaty Teşekkürler! Aslında, buraya kaydedilecek bir sürü bayt var. Şu anda daha iyi bir çözüm ve bir açıklama yazıyorum.
BrainSteel

@ yo 'Çıkışı biraz karıştırdığınızı düşünüyorum. 143521 numaralı kişi çıktısı en sol pisuarın seçti. # 2 kişi en sağdaki kişiyi seçti, sonra da # 3 ortaları zorladı. Çıkması gereken, sonradan toplanan pisuarın numarası değil.
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)

Özyinelemeli yaklaşım.


4

JavaScript (ES6) 153 160 169

Düzen (tabii ki) bulmak için maksimum mesafe Math.min kullanma: aerodinamik kod ve kaydedilmiş 16 bayt.

Özyinelemeli arama, n> 10 ile çalışabilir, sadece% 10 değerini kaldırabilir (ve konsol tüm çıktısını kaldırırken beklemeye hazır olun).

Kullanılan yuvayı (pozitif sayılar) veya en yakın yuvaya olan geçerli mesafeyi (negatif sayılar <ve >kodla değiştirilir) depolamak için tek bir dizi kullanırım .

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
}

Firefox / FireBug konsolunda test edin

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


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]

@ MartinBüttner n~f~s~Join~{#}olacak Join[f[n,s],{#}].
alephalpha

Doğru, doğru ilişkisel olduğunu düşündüm.
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

1

Perl, 174

Çok kısa değil ama eğlenceli. use feature 'say';Bayt toplamını saymıyorum .

$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-golfed:

$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;
}

1

C, 248 bayt

Bu kod istenen sonucu elde etmek için özyinelemeli bir algoritma kullanır.

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);}

Expanded:

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);
}

1

Bash, 744 674 bayt

Bu hala çok uzun bir yol :). Pisuvarların sırasını temsil eden bir dize ve yinelemenin her aşamasında en uzak pisuarları bulmak için bir sel algoritması kullanıyorum. Yalıtılmamış kod neredeyse kendi kendini açıklar niteliktedir. Pisuarların sayısı klavyeden okunur.

Kod (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

kullanın:

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

Ve ungolfed gider:

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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.