Писсуарный протокол


38

Задний план

Так называемый «Протокол мочеиспускания», описывающий порядок, в котором отдельные писсуары отбираются в мужской ванной комнате, обсуждался во многих местах. Одна версия приведена в этом сообщении блога xkcd . Этот вопрос касается небольшого изменения:

Расположение : n писсуаров в ряд.
Протокол : каждый новый человек выбирает один из писсуаров, наиболее удаленных от уже используемых.

Обратите внимание, что это не накладывает никаких ограничений на выбор писсуара первым человеком.

Обновление : последовательность из числа различных способов, которыми n человек могут выбрать n писсуаров, начинается с 1, 2, 4, 8, 20 ... Обратите внимание, что это не то же самое, что OEIS A095236 , который описывает более строгие ограничения, чем в этом вопрос.

задача

Учитывая целое число n от 0 до 10, выведите (в любом порядке) все возможные упорядочения, в которых n человек могут занимать n писсуаров. Каждый порядок должен быть напечатан в качестве окончательного варианта: последовательность цифр, представляющих людей (1-9 для первых 9 человек, 0 для десятого), начиная с самого левого писсуара, с необязательными не алфавитно-цифровыми разделителями между (но не перед или после) цифры. Например, следующие выходные данные являются действительными:

>> 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 (или ближайшую альтернативу), аргумент командной строки или аргумент функции. Результаты должны быть напечатаны в STDOUT (или ближайшую альтернативу).

счет

Самый короткий код выигрывает. Применяются стандартные условия.


1
Гектометр За 5 писсуаров я получаю это . Вместо этого должно быть 16 строк. Кто-нибудь, пожалуйста, уточните, какие из этих решений являются неправильными? Это в настоящее время реализуется: Выберите любой из писсуаров с максимальным расстоянием до кого-либо еще.
knedlsepp

1
Вот вам и песочница :-( Спецификация соответствует описанию в задании, а не определению последовательности. Я обновлюсь, как только доберусь до компьютера.
Ури Гранта

1
@knedlsepp Строки 3, 4, 17, 18 неверны. В них вы помещаете человека № 3 в spanдлину 1, где есть spanдоступная длина 2. Мне вдруг удалось запутаться. Похоже, что OP намеренно получен из ссылки, и, следовательно, ссылка должна следовать?
BrainSteel

Обновлена ​​спецификация, чтобы отметить, что задача не совпадает с A095236.
Ури Гранта

Разрешено ли выводить формат в [1, 3, 2], где каждое такое решение разделяется переводом строки? (так что не только разделитель «,», но также начало «[» и конец «]»)
orlp

Ответы:


11

Pyth, 53 51

MhSm^-dG2HjbmjdmehxkbQusmm+dkfqgTdeSmgbdQUQGUtQm]dQ

Это итеративный подход. Учитывая возможные частично заполненные упорядоченные наборы местоположений, мы находим все оптимальные дальнейшие местоположения, затем генерируем соответствующий список местоположений и повторяем.

Результаты генерируются в форме [<first person's location>, <second person's location> ...], затем она преобразуется в нужный формат. MhSm^-dG2Hопределяет вспомогательную функцию, которая находит минимальные расстояния от данного киоска до занятого киоска (в квадрате). Забавно, разделитель бесплатный.

Пример запуска.

Объяснение:

Во-первых, вспомогательная функция g, которая находит минимальное квадратное расстояние между G и любым значением в H.

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

Затем мы находим максимальное расположение писсуаров на минимальном квадрате расстояния между этим писсуаром и любым занятым писсуаром:

( Qэто вход.)

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

dв этом случае список занятых писсуаров, в то время как bитерирует по местоположениям писсуара.

Затем мы находим все места для писсуаров, минимальное квадратичное расстояние от ближайшего занятого писсуара равно максимальному значению, указанному выше.

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

Далее мы сгенерируем списки местоположений писсуаров, добавив найденные выше местоположения писсуаров d. Мы сделаем это для каждого предыдущего списка мест расположения писсуаров, тем самым расширив списки от длины Nдо N+1. Gэто список юридических списков занятых мест для писсуаров заданной длины.

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

Далее, мы будем применять вышеупомянутое выражение несколько раз, чтобы сгенерировать полный список списков занятых мест писсуара. uФункция Reduce делает это ровно столько раз, сколько элементов содержится во втором аргументе.

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>, ... ], в желаемую форму выходного, [<person in slot 1>, <person in slot 2>, ... ]. Затем форма вывода объединяется в строку вывода и печатается. Печать неявная.

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

Черт, я должен прекратить писать рекурсивные решения в Pyth. Меня всегда бьют: P
orlp

kajsdlkas^23asdjkla1lasdkj~JZasSSA- почти вдвое меньше.
Оптимизатор

@ Оптимизатор Я добавлю объяснение, когда я менее занят.
Исаак

8

Pyth, 75 71 67

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

Рекурсивное комбинаторное решение.

Это довольно прямой перевод из этого решения 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)))

Как это работает? Более подробно, чем «рекурсивное комбинаторное решение».
tbodt

@tbodt Добавил код Python, который я написал перед переводом на Pyth.
orlp

5

C 929 878 байт

Это монстр, ребята. Сожалею.

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

Определяет 3 функции, f(int*,int), P(int*,int,int,int,int)и L(int). Звоните L(n), и он выводит на STDOUT.

Выход для n=5:

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

Обновление: я удалил разделители и исправил код. Старый код не только не работал при n = 7 +, но и вообще ничего не выводил при n = 10 (упс!). Я более тщательно проверил эту связку. Теперь он поддерживает ввод до n = 13 (хотя "%d"следует изменить на "%x"так, чтобы он печатался в шестнадцатеричном формате). Размер ввода зависит, sizeof(long)и предполагается, что 8на практике.

Вот некоторые объяснения того, как это работает, и почему существует такое странное ограничение:

Они часто использовались, поэтому мы определяем их, чтобы сохранить пару байтов:

typedef unsigned long U; typedef unsigned char C;

Вот 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;
}

fпринимает массив целых чисел размера nи nсам. Единственный умный бит здесь - это то, что он возвращает значение unsigned long, которое преобразуется в char[8]вызывающую функцию. Таким образом, каждому символу в массиве присваивается 0xFFиндекс или указатель на действительный писсуар для следующего человека. Для n<10, мы никогда не нужно больше , чем 5 байт для хранения каждого действительного писсуара следующего человек может использовать.

Вот 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);
    }
}

Pпринимает массив uразмера , в nкотором ровно один элемент установлен на 1, а остальные 0. Затем он находит и печатает каждую возможную перестановку рекурсивно.

Вот 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);
    }
}

Lпросто звонит P nраз с разными стартовыми позициями каждый раз.

Для заинтересованных, это (менее гольф) fбудет генерировать последовательность в 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;
}

«1 4 ...» в начале, кажется, противоречит спецификации: если первое число равно 1, следующее должно быть 5.
anatolyg

2
@anatolyg Нет. Вот пошаговое объяснение того, как может произойти «1 4»: gist.github.com/orlp/a5706ba664b70209b48a
orlp

Помните, разделители не являются обязательными. Вы можете сэкономить 1 байт (!), Удалив пробел после% d :-)
Uri Granta

@UriZarfaty Спасибо! На самом деле, здесь нужно сохранить тонну байтов. Я сейчас пишу лучшее решение и объяснение.
BrainSteel

@yo 'Я думаю, ты немного путаешь вывод. Вывод 14352средства № 1 выбрал самый левый писсуар. Человек № 2 выбрал самый правый, который затем заставил № 3 в середине. Это не номер писсуара, выбранного следующим, который должен быть выведен.
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)

Рекурсивный подход.


4

JavaScript (ES6) 153 160 169

Редактировать Используя Math.min, чтобы найти (конечно) максимальное расстояние: оптимизированный код и 16 байтов сохранены.

Рекурсивный поиск может работать с n> 10, просто удалите% 10 (и будьте готовы подождать, пока консоль развернет все свои выходные данные).

Я использую один массив для хранения используемого слота (положительные числа) или текущего расстояния от ближайшего слота (отрицательные числа так <и >меняются местами в коде).

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

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~{#}станет Join[f[n,s],{#}].
алефальфа

Ах да, я думал, что это было правильно ассоциативно.
Мартин Эндер

1

МАТЛАБ, 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

Не очень коротко, но весело. Я не рассчитываю use feature 'say';на общее количество байтов.

$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

Де-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 байт

Этот код использует рекурсивный алгоритм для получения желаемого результата.

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

Баш, 744 674 байта

Это все еще слишком долго :). Я использую строку для представления ряда писсуаров и алгоритм затопления, чтобы найти самые отдаленные писсуары на каждом этапе рекурсии. Негольфированный код почти не требует пояснений. Количество писсуаров читается с клавиатуры.

Код (игра в гольф):

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

Использование:

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

И это разворачивается:

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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.