Знаходжанне п-ю перастаноўку без вылічэнні іншых

Улічваючы масіў N элементаў, якія ўяўляюць сабой атамы перастановак, ці існуе алгарытм, які, як:

function getNthPermutation( $atoms, $permutation_index, $size )

дзе $ атамаў гэта масіў элементаў, $ permutation_index з'яўляецца індэксам перастаноўкі і $ памер з'яўляецца памер перастаноўкі.

Напрыклад:

$atoms = array( 'A', 'B', 'C' );
// getting third permutation of 2 elements
$perm = getNthPermutation( $atoms, 3, 2 );

echo implode( ', ', $perm )."\n";

друкаваць Ці:

B, A

Без вылічэнні кожнай перастаноўкі да $ permutation_index?

Я чуў сёе-тое пра factoradic перастановак, але кожная рэалізацыя я знайшоў дае ў выніку перастаноўкі з тым жа памерам V, які не мой выпадак.

Дзякуючы.

36
Уявіце, што вы надрукаваць кожную перастаноўку N элементаў з яго ітэрацыі лічыльніка (перастаноўка 0, перастаноўка 1, перастаноўка 2, ...) ... я хачу п-й перастаноўку.
дададзена аўтар Simone Margaritelli, крыніца
я не клапачуся аб сартаванні перастановак, любы будзе рабіць гэтую працу :)
дададзена аўтар Simone Margaritelli, крыніца
калі вы не клапоціцеся аб замове, вы можаце проста выбраць любую перастаноўку памеру $ памеру, які вам падабаецца. Вы хочаце, каб выклікаць гэтую функцыю некалькі разоў кожны раз з іншым індэксам?
дададзена аўтар galchen, крыніца
але тое, што вызначае парадак перастаноўкі? я маю на ўвазе, перастаноўка з індэксам 0 можа быць любы з формаў
дададзена аўтар galchen, крыніца
што вы маеце на ўвазе індэкс перастаноўкі?
дададзена аўтар galchen, крыніца

7 адказы

Як заявіла RickyBobby, пры разглядзе пытання аб лексікаграфічным парадку перастановак, вы павінны выкарыстоўваць факторная разлажэнне ў вашых інтарэсах.

З практычнага пункту гледжання, гэта, як я бачу гэта:

  • Выканайце свайго роду Еўкліда дзялення, за выключэннем вы робіце гэта з факторных лікамі, пачынаючы з (п-1)! , (п-2)! , і так на.
  • Трымайце дробу ў масіве. <�Код> я -м фактар ​​павінен быць лікам ад 0 і ш-1 ўключна, дзе я ідзе ад < код> 0 да п-1 .
  • Гэты масіў з'яўляецца Ваша перастаноўка. Праблема заключаецца ў тым, што кожны фактар ​​не клапоціцца аб папярэдніх значэнняў, так што вам трэба наладзіць іх. Больш дакладна, вам трэба павялічваць кожнае значэнне столькі разоў, колькі папярэднія значэння, якія менш або роўныя.

Наступны код C павінен даць вам ўяўленне пра тое, як гэта працуе ( п гэта колькасць запісаў, і я з'яўляецца індэксам перастаноўкі):

/**
 * @param n The number of entries
 * @param i The index of the permutation
 */
void ithPermutation(const int n, int i)
{
   int j, k = 0;
   int *fact = (int *)calloc(n, sizeof(int));
   int *perm = (int *)calloc(n, sizeof(int));

  //compute factorial numbers
   fact[k] = 1;
   while (++k < n)
      fact[k] = fact[k - 1] * k;

  //compute factorial code
   for (k = 0; k < n; ++k)
   {
      perm[k] = i/fact[n - 1 - k];
      i = i % fact[n - 1 - k];
   }

  //readjust values to obtain the permutation
  //start from the end and check if preceding values are lower
   for (k = n - 1; k > 0; --k)
      for (j = k - 1; j >= 0; --j)
         if (perm[j] <= perm[k])
            perm[k]++;

  //print permutation
   for (k = 0; k < n; ++k)
      printf("%d ", perm[k]);
   printf("\n");

   free(fact);
   free(perm);
}

Напрыклад, ithPermutation (10, 3628799) друкуе, як і чакалася, апошняя перастаноўка дзесяці элементаў:

9 8 7 6 5 4 3 2 1 0
41
дададзена
+1 тнх Фелікса для рэалізацыі :)
дададзена аўтар Ricky Bobby, крыніца
Гэта было менавіта рэалізацыя я шукаў, то «п» аргумент з'яўляецца ключом ... дзякуй тааак шмат :)
дададзена аўтар Simone Margaritelli, крыніца
Метад, які выкарыстоўваецца тут, каб атрымаць factoradic/код Лехмера (выкарыстоўвае вылічаныя факториалы і крамы дробаў ня рэшткі) адрозніваюцца ад апісаных на старонцы Вікіпедыі аб Factoradic толькі крыху вышэй раздзеле Прыклады. Выхад, як я праверыў гэта тое ж самае, аднак я лічу, апошні спосаб прасцей. Тым не менш, ваш прыклад дапамог мне зразумець канцэпцыю лепш.
дададзена аўтар konsolebox, крыніца

Вось рашэнне, якое дазваляе выбраць памер перастаноўкі. Напрыклад, акрамя таго, што здольна генераваць ўсе перастаноўкі элементаў 10, ён можа генераваць перастаноўкі пар з 10 элементаў. Акрамя таго, перастаўляе спісы адвольных аб'ектаў, а не толькі цэлыя лікі.

Гэта PHP, але ёсць таксама JavaScript і Haskell impementation.

function nth_permutation($atoms, $index, $size) {
    for ($i = 0; $i < $size; $i++) {
        $item = $index % count($atoms);
        $index = floor($index/count($atoms));
        $result[] = $atoms[$item];
        array_splice($atoms, $item, 1);
    }
    return $result;
}

Прыклад выкарыстання:

for ($i = 0; $i < 6; $i++) {
    print_r(nth_permutation(['A', 'B', 'C'], $i, 2));
}
// => AB, BA, CA, AC, BC, CB

<�Моцны> Як гэта працуе?

Там вельмі цікавая ідэя ззаду яго. Давайце возьмем спіс A, B, C, D . Мы можам пабудаваць перастаноўку малюючы элементы з яго, як з калоды карт. Першапачаткова мы можам зрабіць адзін з чатырох элементаў. Тады адзін з трох пакінутых элементаў, і гэтак далей, пакуль, нарэшце, у нас няма нічога не засталося.

Decision tree for permutations of 4 elements

Вось адзін з магчымых паслядоўнасцяў выбару. Пачынаючы з вяршыні мы бярэм трэці шлях, то першы, другі, і, нарэшце, першы. І гэта наша перастаноўка # 13.

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

Давайце паспрабуем знайсці агульную схему для ўпакоўкі паслядоўнасць выбару ў цэлы лік без надмернасці і распакавання яго назад.

Адна цікавая схема завецца дзесятковай сістэмай злічэння. «27» можна разглядаць як выбар шляху # 2 з 10, а затым выбраць шлях # 7 з 10.

Decision three for number 27 in decimal

Але кожная лічба можа кадзіраваць толькі выбар з 10 варыянтаў. Іншыя сістэмы, якія маюць фіксаваны дзесятковы, як двайковыя і шаснаццатковай, таксама могуць кадзіраваць толькі паслядоўнасць выбару з фіксаванага колькасці альтэрнатыў. Мы хочам, каб сістэма з пераменным радиксом, накшталт як адзінкі часу, «14:05:29» ў гадзіне 14 ад 24, 5 хвілін ад 60, другое 29 з 60.

Што рабіць, калі мы возьмем агульная колькасць ў радок і радок-лік функцый, і падмануць іх у выкарыстанні змешанага radixes? Замест таго, каб адзін дзесятковую, як ParseInt ( «ялавічына» , 16) і (48879) .ToString (16) , яны будуць прымаць адну дзесятковую за кожную лічбу.

function pack(digits, radixes) {
    var n = 0;
    for (var i = 0; i < digits.length; i++) {
        n = n * radixes[i] + digits[i];
    }
    return n;
}

function unpack(n, radixes) {
    var digits = [];
    for (var i = radixes.length - 1; i >= 0; i--) {
        digits.unshift(n % radixes[i]);
        n = Math.floor(n/radixes[i]);
    }
    return digits;
}

Ці значыць гэта нават працуе?

// Decimal system
pack([4, 2], [10, 10]);//=> 42

// Binary system
pack([1, 0, 1, 0, 1, 0], [2, 2, 2, 2, 2, 2]);//=> 42

// Factorial system
pack([1, 3, 0, 0, 0], [5, 4, 3, 2, 1]);//=> 42

А цяпер назад:

unpack(42, [10, 10]);//=> [4, 2]

unpack(42, [5, 4, 3, 2, 1]);//=> [1, 3, 0, 0, 0]

Гэта так прыгожа. Зараз давайце выкарыстоўваецца і ў дачыненні гэтую параметрычных сістэму злічэння да праблемы перастановак. Мы будзем разглядаць даўжыню 2 перастановак A, B, C, D . Што агульная іх колькасць? Давайце паглядзім: спачатку намаляваць адзін з 4-х элементаў, то адзін з пакінутых 3, гэта 4 * 3 = 12 спосаб малявання 2 пунктаў. Гэтыя 12 спосабаў могуць быць спакаваныя ў цэлыя лікі [0..11]. Такім чынам, давайце ўявім, што мы іх спакавалі ўжо і паспрабаваць распакаванні:

for (var i = 0; i < 12; i++) {
    console.log(unpack(i, [4, 3]));
}

// [0, 0], [0, 1], [0, 2],
// [1, 0], [1, 1], [1, 2],
// [2, 0], [2, 1], [2, 2],
// [3, 0], [3, 1], [3, 2]

Гэтыя лічбы ўяўляюць сабой выбар, а не індэксы ў зыходным масіве. [0, 0] не азначае прымаць A, A , гэта азначае, прымаючы пункт # 0 з A, B, C, D (гэта А), а затым дэталь # 0 з таго, хто застаўся спісу B, C, D (гэта Б). І ў выніку перастаноўкі A, B .

Іншы прыклад: [3, 2] азначае, прымаючы пункт # 3 ад А, У, З, D (гэта D), а затым пункт # 2 з пакінутага спісу A, B, C (гэта C). І ў выніку перастаноўкі D, C .

Гэта адлюстраванне называецца Лехмер код . Давайце супаставіць усе гэтыя коды Лехмера перастановак:

AB, AC, AD, BA, BC, BD, CA, CB, CD, DA, DB, DC

Гэта менавіта тое, што нам трэба. Але калі вы паглядзіце на распакоўваць функцыі вы заўважыце, што яна вырабляе лічбы справа налева (для зваротнага дзеяння пакет ). Выбар з 3 атрымлівае распакаваны перад выбарам з 4. Гэта сумна, таму што мы хочам, каб выбраць адзін з 4-х элементаў, перш чым выбраць з 3. Не будучы ў стане зрабіць гэта, мы павінны вылічыць код Лехмер першым, назапашваюць яго ў часовы масіў, а затым прымяніць яго да масіву элементаў для вылічэнні фактычнай перастаноўкі.

Але калі мы не будзем клапаціцца пра лексікаграфічным парадку, мы можам рабіць выгляд, што мы хочам, каб выбраць адзін з 3-х элементаў, перш чым выбраць з 4. Тады выбар з 4 выйдзе з распакаванні першы. Іншымі словамі, мы будзем выкарыстоўваць распакоўваць (п, [3, 4]) замест распакоўваць (п, [4, 3]) . Гэты трук дазваляе вылічыць наступную лічбу Лемер кода і адразу ж прымяніць яго да спісу. І гэта менавіта тое, як nth_permutation() працуе.

Адна апошняя рэч, якую я хачу згадаць пра тое, што распакоўваць (я, [4, 3]) цесна звязана з сістэмай фактарыяла колькасці. Паглядзіце на гэта першае дрэва зноў, калі мы хочам, каб перастаноўкі даўжыні 2 без дубляў, мы можам проста прапусціць кожны другі індэкс перастаноўкі. Гэта дасць нам 12 перастановак даўжыні 4, якія могуць быць аздоблены па даўжыні 2.

for (var i = 0; i < 12; i++) {
    var lehmer = unpack(i * 2, [4, 3, 2, 1]);//Factorial number system
    console.log(lehmer.slice(0, 2));
}
25
дададзена

Гэта залежыць ад таго, вы «сартаваць» вашыя падстаноўкі (лексікаграфічныя парадак, напрыклад).

Адзін са спосабаў зрабіць гэта з'яўляецца факторный нумар сістэмы , гэта дае ўзаемна адназначнае адпаведнасць паміж [0, п] і ўсе перастаноўкі.

Тады для любога ліку я ў [0, п] можна вылічыць ю перастаноўку без вылічэнні астатніх.

Гэта факторный пісьменнасць засноўваецца на тым, што любы лік паміж 0 і [п!] Можна запісаць у выглядзе:

SUM( ai.(i!) for i in range [0,n-1]) where ai 

(Гэта вельмі падобна на базавыя декомпозиции)

for more information on this decomposition, have a look at this thread : https://math.stackexchange.com/questions/53262/factorial-decomposition-of-integers

спадзяюся, што гэта дапамагае


Як паказана на гэтай вікіпедыі артыкула гэтага падыходу з'яўляецца тое, што эквівалентна вылічэнню Лехмер код :

<�Р> Відавочны спосаб генерацыі перастановак п з'яўляецца атрыманне значэнняў   код Лехмер (магчыма з выкарыстаннем сістэмы фактарыяла колькасці   прадстаўленне цэлых лікаў да п!), а таксама канвертаваць гэтыя ў   адпаведныя перастаноўкі. Аднак апошні крок, у той час як   проста, цяжка эфектыўна рэалізаваць, паколькі яна патрабуе   п аперацыі кожны з выбару з паслядоўнасці і выдаленні ад яго,   ў адвольным становішчы; з відавочных уяўленняў аб   паслядоўнасць у выглядзе масіва або звязанага спісу, як патрабуецца (для розных   прычыны) каля n2/4 аперацый, каб выканаць пераўтварэнне. З п   хутчэй за ўсё, будзе дастаткова мала (асабліва калі пакаленнем ўсіх   Перастаноўкі неабходна), не занадта вялікая праблема, але   Аказваецца, што і для выпадковых і сістэматычных пакалення там   простыя варыянты, якія робяць значна лепш. Па гэтай прычыне   не падаецца карысным, хоць, вядома, магчыма, выкарыстоўваць спецыяльны   структура дадзеных, якая дазволіла б выконваць пераўтварэнне з Лехмера   код перастаноўкі ў Аб (п) ўвайсці п раз. </р>

Такім чынам, лепшае, што вы можаце зрабіць для набору п элемента Аб (п п (п)) з адаптаванай структурай дадзеных.

14
дададзена
@SimoneMargaritelli Што вы маеце на ўвазе? Вы хочаце перастаноўку аднаго падмноства зыходнага мноства элементаў?
дададзена аўтар Ricky Bobby, крыніца
я ўжо ў курсе фактарнай сістэмы злічэння, але я не магу знайсці рэалізацыю, дзе памер выхадны перастаноўкі не тое ж самы з зыходнага вектара элементаў.
дададзена аўтар Simone Margaritelli, крыніца
Вы маглі б на самай справе O (N для LG U) з дапамогай VEB дрэў, так як U = п. Цікава, што ніжняя мяжа ??
дададзена аўтар dhruvbird, крыніца

Вось алгарытм для пераўтварэння паміж перастаноўкамі і рангу ў лінейнае час. Тым не менш, рэйтынг выкарыстоўвае ня лексікаграфічныя. Гэта дзіўна, але паслядоўна. Я збіраюся даць дзве функцыі, адна з якіх пераходзіць з рангу перастаноўкі, і адзін, што робіць адваротнае.

Па-першае, unrank (перайсці ад рангу да перастаноўкі)

Initialize:
n = length(permutation)
r = desired rank
p = identity permutation of n elements [0, 1, ..., n]

unrank(n, r, p)
  if n > 0 then
    swap(p[n-1], p[r mod n])
    unrank(n-1, floor(r/n), p)
  fi
end

Далей у рэйтынгу:

Initialize:
p = input permutation
q = inverse input permutation (in linear time, q[p[i]] = i for 0 <= i < n)
n = length(p)

rank(n, p, q)
  if n=1 then return 0 fi
  s = p[n-1]
  swap(p[n-1], p[q[n-1]])
  swap(q[s], q[n-1])
  return s + n * rank(n-1, p, q)
end

Час працы абодвух з іх уяўляе сабой Аб (п).

There's a nice, readable paper explaining why this works: Ranking & Unranking Permutations in Linear Time, by Myrvold & Ruskey, Information Processing Letters Volume 79, Issue 6, 30 September 2001, Pages 281–284.

http://webhome.cs.uvic.ca/~ruskey/Publications/RankPerm/MyrvoldRuskey. PDF

7
дададзена
Гэта рашэнне, верагодна, самыя хуткім, таму што вы не павінны рабіць масіў сплайсинг (або элемент выдаленні) і няма укладзенай для завес +1.
дададзена аўтар James, крыніца

Вось кароткі і вельмі хутка (лінейны па ліку элементаў) рашэнняў у пітонаў, працуючы для любога спісу элементаў (13 першых літар у прыкладзе ніжэй):

from math import factorial

def nthPerm(n,elems):#with n from 0
    if(len(elems) == 1):
        return elems[0]
    sizeGroup = factorial(len(elems)-1)
    q,r = divmod(n,sizeGroup)
    v = elems[q]
    elems.remove(v)
    return v + ", " + ithPerm(r,elems)

прыклады:

letters = ['a','b','c','d','e','f','g','h','i','j','k','l','m']

ithPerm(0,letters[:])          #--> a, b, c, d, e, f, g, h, i, j, k, l, m
ithPerm(4,letters[:])          #--> a, b, c, d, e, f, g, h, i, j, m, k, l
ithPerm(3587542868,letters[:]) #--> h, f, l, i, c, k, a, e, g, m, d, b, j

Заўвага: Даю літары [:] (копія лісты ), а не літары, таму што функцыя змяняе свой параметр elems (выдаляе абраны элемент)

4
дададзена
Што адбудзецца, калі ваш спіс змяшчае паўтараюцца сімвалы? Гэта вырабляе няправільны вынік.
дададзена аўтар Sonu Kumar, крыніца

Калі вы захоўваеце ўсе перастаноўкі ў памяці, напрыклад, у масіве, вы павінны быць у стане вярнуць іх назад па адным за раз у O (1) час.

Гэта азначае, што вы павінны захоўваць усе перастаноўкі, так што, калі вылічэнне ўсіх перастановак займае недапушчальна доўгі час, або іх захоўванне займае недапушчальна вялікая прастора, то гэта не можа быць рашэннем.

Мая прапанова было б паспрабаваць яго ў любым выпадку, і вярнуцца, калі ён занадта вялікім/павольна - няма ніякага сэнсу шукаць «разумнае» рашэнне, калі наіўны адзін будзе рабіць гэтую працу.

1
дададзена
Добра, вы маеце рацыю, гэта тое, што вы хочаце пачуць? :) Гэта было проста непаразуменне, лягчэй чувак;)
дададзена аўтар Simone Margaritelli, крыніца
я думаю, што гэта было свайго роду відавочная, так як я сказаў «... Без вылічэнні кожнай перастаноўкі ...» ...
дададзена аўтар Simone Margaritelli, крыніца
калі я пытаюся гэта таму, што я ўжо пратэставаны з папярэдне вылічаным перастаноўкамі ...
дададзена аўтар Simone Margaritelli, крыніца
Не магу супраціўляцца. Алгарытм, які выкарыстоўвае предвычисленные перастаноўкі не вылічае ніякіх перастановак. (Я тут толькі таму, што я знайшоў гэтае пытанне і іншыя адказы карысныя).
дададзена аўтар dansalmo, крыніца
+1 за тое, што Сымону ня адказ на пытанне, ён меў на ўвазе, каб спытаць, але адказ на пытанне, на самай справе ён прасіў.
дададзена аўтар Patrick87, крыніца
прабачце, мае псіхічныя сілы павінны быць няўдача мяне сёння - небудзь або што вы кладзеце гэтую інфармацыю ў вельмі невялікай тэксце ў вашым пытанні.
дададзена аўтар Chris Browne, крыніца
Вы на самой справе заявілі, што «без вылічэнні не кожны перастаноўкі да $ permutation_index», якая не з'яўляецца такім жа, як «без вылічэнні кожнай перастаноўкі». Гэта першы раз, калі я калі-небудзь бачыў хто-то цытата <�я> сябе </я> з кантэксту!
дададзена аўтар Chris Browne, крыніца
Ага, ты перахітрыў мяне, выкарыстоўваючы стары «супакойваць» трук. Любы адказ цяпер я пішу будзе гучаць злуе, што можа негатыўна паўплываць на маю рэпутацыю! Ніколі не пярэчыць, я не занадта мітусіліся «выйгрышныя аргументы» у любым выпадку, больш зацікаўлены ў прыняцці рэальнага прагрэсу.
дададзена аўтар Chris Browne, крыніца
Гэта два гады адказ, іншыя адказы на гэтае пытанне цалкам здавальняючыя, так што я не бачу ніякай неабходнасці рэдагаваць уласны (ва ўсякім выпадку, я быў бы схільны проста выдаліць яго). Маё стаўленне да дапытваюць будзе нашмат больш сціплым і даруючы гэтыя дні, для запісу. Я думаю, што я быў проста дрэнны дзень на 27 кастрычніка 2011 года.
дададзена аўтар Chris Browne, крыніца

Гэта вылічае. Гэта C# код, які робіць гэта для вас.

using System;
using System.Collections.Generic;

namespace WpfPermutations
{
    public class PermutationOuelletLexico3
    {
       //************************************************************************
        private T[] _sortedValues;

        private bool[] _valueUsed;

        public readonly long MaxIndex;//long to support 20! or less 

       //************************************************************************
        public PermutationOuelletLexico3(T[] sortedValues)
        {
            if (sortedValues.Length <= 0)
            {
                throw new ArgumentException("sortedValues.Lenght should be greater than 0");
            }

            _sortedValues = sortedValues;
            Result = new T[_sortedValues.Length];
            _valueUsed = new bool[_sortedValues.Length];

            MaxIndex = Factorial.GetFactorial(_sortedValues.Length);
        }

       //************************************************************************
        public T[] Result { get; private set; }

       //************************************************************************
        /// 
/// Return the permutation relative to the index received, according to /// _sortedValues. /// Sort Index is 0 based and should be less than MaxIndex. Otherwise you get an exception. ///
 
        /// 
        /// 
Value is not used as inpu, only as output. Re-use buffer in order to save memory
        /// 
        public void GetValuesForIndex(long sortIndex)
        {
            int size = _sortedValues.Length;

            if (sortIndex < 0)
            {
                throw new ArgumentException("sortIndex should be greater or equal to 0.");
            }

            if (sortIndex >= MaxIndex)
            {
                throw new ArgumentException("sortIndex should be less than factorial(the lenght of items)");
            }

            for (int n = 0; n < _valueUsed.Length; n++)
            {
                _valueUsed[n] = false;
            }

            long factorielLower = MaxIndex;

            for (int index = 0; index < size; index++)
            {
                long factorielBigger = factorielLower;
                factorielLower = Factorial.GetFactorial(size - index - 1); // factorielBigger/inverseIndex;

                int resultItemIndex = (int)(sortIndex % factorielBigger/factorielLower);

                int correctedResultItemIndex = 0;
                for(;;)
                {
                    if (! _valueUsed[correctedResultItemIndex])
                    {
                        resultItemIndex--;
                        if (resultItemIndex < 0)
                        {
                            break;
                        }
                    }
                    correctedResultItemIndex++;
                }

                Result[index] = _sortedValues[correctedResultItemIndex];
                _valueUsed[correctedResultItemIndex] = true;
            }
        }

       //************************************************************************
        /// 
/// Calc the index, relative to _sortedValues, of the permutation received /// as argument. Returned index is 0 based. ///
 
        /// 
        /// 
        public long GetIndexOfValues(T[] values)
        {
            int size = _sortedValues.Length;
            long valuesIndex = 0;

            List valuesLeft = new List(_sortedValues);

            for (int index = 0; index < size; index++)
            {
                long indexFactorial = Factorial.GetFactorial(size - 1 - index);

                T value = values[index];
                int indexCorrected = valuesLeft.IndexOf(value);
                valuesIndex = valuesIndex + (indexCorrected * indexFactorial);
                valuesLeft.Remove(value);
            }
            return valuesIndex;
        }

       //************************************************************************
    }
}
0
дададзена