Как мне заполнить массив случайными числами, чтобы они были разными?

У меня есть задача, в которой я должен заполнить массив 16 случайными числами в случайных индексах.

4 из этих элементов должны иметь значение -1, а все остальные левые индексы должны быть 0-15, но отличаться от другого, то есть невозможно, чтобы два разных индекса имели одинаковый номер (0-15).

Заполнить 4 случайных индекса легко, как и другие индексы случайными числами от 0 до 15, но как я чувствую их таким образом, чтобы они обязательно отличались друг от друга?

Есть еще два условия, которые еще больше усложняют эту задачу: первое - это то, что номер индекса не может иметь одинаковый номер внутри него, что означает невозможность arr[3] == 3, а другое условие заключается в том, что

    (m[p] == j && m[j] == mp && m != j)

это то, о чем мы должны позаботиться, чтобы этого не произошло. Например, если arr[2] == 0 и arr[0] == 2, мы должны изменить это, чтобы этого не произошло.

Я так сбит с толку, вчера я буквально 8 часов просидел перед этим, пробуя все что угодно, и, честно говоря, я понятия не имею ...

void FillArray(int *sites, int length) 
{
    int checkarr[N] = { 0 };
    int i, 
        cnt = 0, 
        j = 0, 
        t = 0, 
        k, 
        times = 0;
    int *p = sites;

    while (cnt < C)
    {
        i = rand() % length;
        if (p[i] - 1)
            cnt = cnt;
        p[i] = -1;
        cnt++;
    }

    while (j < length) 
    {
        if (p[j] == -1) j++;
        else 
        {
            p[j] = rand() % length;
            checkarr[p[j]]++;
            j++;
        }
    }

    j =0;
    while (j<length)
    {
        for (k=0; k<length;k++)
        {
            while (checkarr[k] > 1)
            {
                while (t < length) 
                {
                    if (p[j] == p[t] && p[j] != -1 && j != t)
                    {
                        checkarr[p[t]]--;
                        p[t] = rand() % length;
                        checkarr[p[t]]++;
                        times++;
                    }
                    else t++;
                }

                if (times < 11) 
                { 
                    j++;
                    t = 0;
                    times = 0;
                }
            }
        }
    }
}

Я пробовал использовать метод перемешивания Фишера-Йейтса, но по какой-то причине он даже не заполняет массив. Я не знаю почему

в то время как (j

    if (p[j] == -1)
        j++;
    else {
        while (m < length) {
            m = rand() % length;
            if (helpingArray[m] != -2)
            {
                p[j] = helpingArray[m];
                helpingArray[m] = -2;
                j++;
            }
            else if (helpingArray[m] == -2)
            {
                j = j;
            }

            for (w = 0; w < length; w++)
            {
                if (helpingArray[w] == -2)
                    count++;
            }
            if (count == 12) {
                m = length;
            }
        }
    }
}
}  

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

AJF 08.01.2019 19:45

можешь показать нам свой код? с головы до ног я бы использовал 2 массива aux, чтобы помочь с первыми двумя условиями

H.cohen 08.01.2019 19:47

Я знаю, я просто не знаю, как это преобразовать в код .. Слишком много «раз» и «если», и мне трудно справиться с этим, лол

סמי זלדין 08.01.2019 19:47

Просто заполните массив нужными значениями, но сделайте случайный перестановки

Ctx 08.01.2019 19:47

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

H.cohen 08.01.2019 19:49

@ H.cohen Слишком долго, чтобы вставлять его сюда: \

סמי זלדין 08.01.2019 19:51

Что ж, тогда я добавлю две части: void FillArray (int * sites, int length) {int checkarr [N] = {0}; int i, cnt = 0, j = 0, t = 0, k, раз = 0; int * p = сайты; в то время как (cnt <C) {я = rand ()% длина; если (p [i] - 1) {cnt = cnt; } p [i] = -1; cnt ++; } в то время как (j <длина) {если (p [j] == -1) j ++; иначе {p [j] = rand ()% length; checkarr [п [j]] ++; j ++; }}

סמי זלדין 08.01.2019 19:51

Вопрос из заголовка называется "перемешать". А вот для этого алгоритм Фишер-Йейтс. Однако другие условия являются дополнительными, что потребует дополнительных разъяснений.

Eugene Sh. 08.01.2019 19:52

j = 0; while (j <length) {for (k = 0; k <length; k ++) {while (checkarr [k]> 1) {while (t <length) {if (p [j] == p [t] && p [j]! = -1 && j! = t) {// p [2] = p [3] checkarr [p [t]] -; // checkarr [p [3]] - p [t] = rand ()% length; // p [3] = random checkarr [p [t]] ++; // checkarr [p [3]] ++; раз ++; // раз +1} else t ++; } если (раз <11) {j ++; t = 0; раз = 0; }}}}}

סמי זלדין 08.01.2019 19:52

@ סמיזלדין Пожалуйста, удалите эти комментарии и внесите их в свой вопрос как отредактированный.

Ctx 08.01.2019 19:53

Пожалуйста, редактировать свой вопрос и поместите свой код в блок кода, а не добавляйте его в качестве комментария.

Craig Estey 08.01.2019 19:53

Также поясните, что вы имеете в виду под значениями -1. Если вы заполняете массив 16 случайными значениями в диапазоне 0-15, куда вы хотите поместить значения -1?

Craig Estey 08.01.2019 19:55

@CraigEstey поехали

סמי זלדין 08.01.2019 20:00

@CraigEstey Случайные места, неважно где. четыре элемента должны быть -1, а все остальные двенадцать должны быть в диапазоне 0-15.

סמי זלדין 08.01.2019 20:01

определяется ли N 16 и определяется ли C 12?

H.cohen 08.01.2019 20:06

@ H.cohen, нет, N - 16 и C. Я использую C для заполнения 4 случайных элементов в -1, а затем использую N для просмотра всех элементов и помещаю случайные числа 0-15 только в те, которые не заполнены -1.

סמי זלדין 08.01.2019 20:13

Пожалуйста, предоставьте всю информацию по вашему вопросу. Желательно также превратить его в минимальный воспроизводимый пример.

Yunnosch 08.01.2019 20:21

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

Greg K. 08.01.2019 20:41

@EugeneSh. Я пробовал и понятия не имею, почему не работает? Я выложил это в пост

סמי זלדין 08.01.2019 20:51

Состояние (m[p] == j && m[j] == mp && m != j) не является правильным; mp не определен (опечатка?), А m != j не имеет смысла, поскольку m - это массив, а j - целое число. Что там задумано? Если предполагается, что это будет (m[p] == j && m[j] == p && p 1= j), то, за исключением элементов −1, вы ищете неисправность без подкачки. (Нарушение - это перестановка, при которой ни один элемент не отображается на себя (m[j] != j), а отсутствие подкачки означает отсутствие пары элементов m[a] == b && m[b] == a.

Eric Postpischil 09.01.2019 15:47

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

Eric Postpischil 09.01.2019 15:52

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

Eric Postpischil 09.01.2019 19:22
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
22
1 285
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Ответ принят как подходящий

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

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

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

УДАЧИ

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define N 16
#define C 4

void FillArray(int *sites, int length) {
/*these aux arrays will keep track if an index was fill of if a value was used*/
int checkarrIndex[N] = { 0 };
int checkarrVal[N] = { 0 };

int i, cnt = 0, full=0; /*full is when all index are filled */
int *p = sites;
while (cnt < C) {
    i = rand() % length;
    if (checkarrIndex[i] == 0) /* checkarrIndex will let you know if an index has been gvin a value*/
    {
        ++checkarrIndex[i]; /*now  checkarrIndex[i] will be one so this index is now not valid for placement next time*/
        p[i] = -1;
        ++full;/*at the end of this while full will equal 4*/
        cnt++;
    }

}
while (full < length) /*here you need to draw a random index and a random value for it, 
                  not just a random value for a fixed index like you did, if I got this wrong just
                  go over the free indexes and place a rand value one at a time in the same manner*/
{
    int index; /*will store new random index */
    int value; /*will store new random value */
    index = rand() % N;
    value = rand() % N;/*max value is 15*/
    while(checkarrIndex[index]!= 0) /*check if this index was already placed */
    {
        index = rand() % N; /*try a another one */
    }
    /*I made this while loop to check all the con before filling the array */
    while(checkarrVal[value]!= 0 || p[value]== index || index == value) /*check if this value was already used  or if p[i]=j&&p[j]=i cond happens and make sure p[a] != a*/
    {
        value = rand() % N; /*try a another one */
    }
    ++checkarrIndex[index];/*set index as used */
    ++checkarrVal[value];/*set value as used */
    p[index] = value;
    ++full; /*another place was filled */


  }
}
static void PrintArray(int* arr, size_t size)
{
    int i = 0 ;
    for (i = 0 ; i< size; ++i)
    {
        printf("%d| ", arr[i]);
    }
    printf("\n");
}
int main(void)
{
    int array[N] = {0};
    FillArray(array, N);
    PrintArray(array, N);
    return 0;
}

всегда остаются лишние значения, поэтому я не думаю, что бесконечный цикл возможен. хорошее замечание о p [value] == index. Было бы разумно сначала проверить, что индекс, равный значению, был установлен, прежде чем проверять это. как я уже писал- не тестировал досконально. @EricPostpischil

H.cohen 09.01.2019 16:51

Хорошо, я вижу, что цикл не возникает, потому что вы сначала помещаете четыре элемента -1 и увеличиваете full, поэтому при назначении последнего одного или двух элементов в пуле всегда остается пять или шесть значений, соответственно. (Я должен подумать, как это повлияет на распределение вероятностей.) Вам следует переименовать full и изменить его описание (которое гласит: «Полный - это когда все индексы заполнены»). Это звучит как логическое значение, но на самом деле это количество уже заполненных чисел.

Eric Postpischil 09.01.2019 17:07

Я думаю, что Полон более логический, но я подумаю над этим. tnx для вашего ввода =) @EricPostpischil

H.cohen 09.01.2019 17:10

Думаю на раздачу сказывается. Рассмотрим алгоритм, примененный к N = 4, C = 2. Для решений, в которых последние два элемента равны −1, возможности для первых двух элементов равны [1, 2], [1, 3], [2, 0] , [2, 1], [2, 3], [3, 0], [3, 1] и [3, 2]. Таким образом, с учетом назначения -1, 1 должен появиться в позиции 0 два раза из восьми, но этот алгоритм генерирует его один раз из трех. (Если он сначала занимает позицию 0, он выбирает 1 один раз из трех. Если он сначала занимает позицию 1, он выбирает 0, 2 или 3, а затем вероятность для 1 в позиции 0 равна 0, ½, ½ соответственно. Таким образом, ½ • + ½ • (0 + ½ + ½) / 3 = ⅓.)

Eric Postpischil 09.01.2019 17:58

какой тип распределения, по вашему мнению, предназначен для ОП? ограничения представленного алгоритма влияют на «случайность» выходных данных, но то, распределяются ли -1 случайные индексы первым-последним или между ними, не должно изменять вероятность каждого результата. Я не уверен, что понял, что вы имели в виду в своем примере. @EricPostpischil

H.cohen 09.01.2019 19:09

Математики используют термин «случайный» в техническом смысле для обозначения переменной с возможными значениями, которые являются результатами некоторого случайного процесса, который может иметь разные распределения. Нетехнические пользователи часто используют слово «случайный», чтобы включить равномерное распределение. Есть три возможности: (a) OP предполагал равномерное распределение, которого этот ответ не обеспечивает. (b) OP предполагал какое-то конкретное распределение, о котором не было сказано, и поэтому нет оснований полагать, что распределение, полученное с помощью этого ответа, соответствует ему. (c) OP не намеревалась какого-либо конкретного распространения, и в этом случае…

Eric Postpischil 09.01.2019 19:19

… Любое решение является удовлетворительным, включая подпрограмму, которая всегда возвращает [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, -1, -1, -1, -1], поскольку это результат извлечения из распределения с вероятностью 1 для этого результата и 0 для других. Я думаю, что (а) наиболее вероятно, но, если это (б), вопрос необходимо прояснить.

Eric Postpischil 09.01.2019 19:20

Мой C заржавел, и я не хочу реализовывать тасование Фишера-Ятса или иметь дело с плохим поведением C PRNG, поэтому я выражаю алгоритм в псевдокоде. Ладно, вру. Это Ruby, но он читается как псевдокод и сильно комментируется, чтобы показать логику решения. Считайте комментарии решением, а то, что между ними - конкретной иллюстрацией того, что описываемый алгоритм действительно работает.

N = 16

# Create + populate an array containing 0,...,N-1
ary = Array.new(N) { |i| i }

# Shuffle it
ary.shuffle!  

# Iterate through the array.  If any value equals its index, swap it with
# the value at the next index, unless it's the last array element
ary.each_index { |i| ary[i], ary[i + 1] = ary[i + 1], ary[i] if ary.length - i > 1 && ary[i] == i }

# If the last element equals its index, swap it with any other element
# selected at random.  The rand function generates a random integer
# between 0, inclusive, and its argument, exclusive.
last = ary.length - 1
if ary[last] == last
  random_index = rand(last)
  ary[last], ary[random_index] = ary[random_index], ary[last]
end

# Replace 4 randomly selected entries with -1
4.times { ary[rand(ary.length)] = -1 }

# The array now contains unique elements (except for the -1's),
# none of which are equal to their index value
p ary

# Produces, e.g.:  [4, 10, -1, 5, 9, -1, 15, 14, 7, 8, 12, 1, -1, 0, -1, 2]

Все это требует O (N) работы. Если ваше последнее ограничение нарушено, отклоните решение и повторите попытку.

[Простая] оптимизация может заключаться в замене любых [до 4] элементов, которые нарушают последнее ограничение (например, ary[x] == x), на -1 и случайным размещением оставшихся значений -1 (если есть). Обнаружение / замена может выполняться за один проход, подсчитывая количество окончательных ячеек нарушения ограничений. Если он <= 4, все готово (опять же случайным образом размещаем все оставшиеся значения -1). В противном случае, как вы упомянули, отклоните решение и повторите попытку.

Craig Estey 08.01.2019 23:45

Исключение элементов, которые сопоставляются сами с собой, путем их замены соседом, сгенерирует более высокую вероятность m[i+1] == i, чем при равномерном распределении.

Eric Postpischil 09.01.2019 16:20

Неясно, что генерация полного присваивания, удовлетворяющего условиям, исключающим −1 элементов, а затем замена некоторых элементов на −1 порождает равномерное распределение по решениям, удовлетворяющим всем условиям. Я думаю, что это может не одобрить решения, в которых назначения содержали бы элемент подкачки или самокопирования, который скрыт элементами -1.

Eric Postpischil 09.01.2019 16:21

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

pjs 09.01.2019 16:30

@pjs: если единообразие не является требованием, тогда процедура, которая всегда возвращает [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, -1, -1, -1, −1] удовлетворяет вопросу, поскольку это просто распределение с вероятностью 1 для этого решения и 0 для остальных. В разговорной речи слово «случайный» часто означает однородный; наивные заказчики случайных выборок обычно подразумевают рисование с равномерным распределением. Если вы не уверены, что они предполагали равномерное распределение, вам следует запросить разъяснения. Конечно, какое бы распределение ни выпало из скомпонованного алгоритма, это не то, что было задумано.

Eric Postpischil 09.01.2019 16:47

@EricPostpischil Случайность не означает единообразия, она определяется отсутствием предсказуемости. Кажется, вы смешиваете случайность с энтропией. Это правда, что равномерное распределение имеет максимальную энтропию Шеннона, но я сомневаюсь, что вы осмелитесь заявить, что другие распределения, такие как гауссово, не являются случайными. Случайность - это все, что требовалось.

pjs 09.01.2019 21:50

@pjs: Я не делал никаких заявлений о случайности или энтропии, за исключением того, что заявлял, что нетехнические ораторы часто просто просят «случайное», когда им нужна униформа. Это не утверждение о математике, а просто наблюдение за множеством примеров. Маловероятно, что простая случайность - это «все», что было желательно, и у них нет никаких ограничений на это, так как какой цели может служить какое-то сильно искаженное распределение, даже не зная об этом?

Eric Postpischil 10.01.2019 03:20

Я не уверен, что полностью, но я думаю, что следующее отвечает всем вашим особым ограничениям [надеюсь].

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

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

Я создал простой случайный список. Затем попробуйте обнаружить / исправить (поменяв местами) некоторые нарушения ограничений.

Затем заполните отрицательными значениями, пытаясь по возможности исправить нарушения самозависимости.

Если это невозможно, повторите весь процесс.

Во всяком случае, вот моя версия. Я разделил большую функцию на несколько более мелких. Я также добавил функцию проверки и цикл диагностики. Он немного отличается от вашего, но другие ответы тоже:

#include <stdio.h>
#include <stdlib.h>

#define NEG     4

int opt_N;
int opt_v;
int opt_T;

#ifdef DEBUG
#define dbg(_fmt...) \
    do { \
        if (opt_v) \
            printf(_fmt); \
    } while (0)
#else
#define dbg(_fmt...)            /**/
#endif

// prtarray -- print array
void
prtarray(int *arr,int len)
{
    int idx;
    int val;
    int hangflg = 0;
    int cnt = 0;

    for (idx = 0;  idx < len;  ++idx) {
        val = arr[idx];
        if (val < 0)
            printf(" [%2.2d]=%d",idx,val);
        else
            printf(" [%2.2d]=%2.2d",idx,val);
        hangflg = 1;

        if (++cnt >= 8) {
            printf("\n");
            cnt = 0;
            hangflg = 0;
            continue;
        }
    }

    if (hangflg)
        printf("\n");
}

// fillrand -- generate randomized list (fisher yates?)
void
fillrand(int *arr,int len)
{
    char idxused[len];
    char valused[len];
    int fillcnt = 0;
    int idx;
    int val;

    for (idx = 0;  idx < len;  ++idx) {
        idxused[idx] = 0;
        valused[idx] = 0;
    }

    for (fillcnt = 0;  fillcnt < len;  ++fillcnt) {
        // get random index
        while (1) {
            idx = rand() % len;
            if (! idxused[idx]) {
                idxused[idx] = 1;
                break;
            }
        }

        // get random value
        while (1) {
            val = rand() % len;
            if (! valused[val]) {
                valused[val] = 1;
                break;
            }
        }

        arr[idx] = val;
    }
}

// swap2 -- swap elements that are (e.g.) arr[i] == arr[arr[i]])
int
swap2(int *arr,int len)
{
    int idx;
    int lhs;
    int rhs;
    int swapflg = 0;

    dbg("swap2: ENTER\n");

    for (idx = 0;  idx < len;  ++idx) {
        lhs = arr[idx];
        rhs = arr[lhs];

        // don't swap self -- we handle that later (in negfill)
        if (lhs == idx)
            continue;

        if (rhs == idx) {
            dbg("swap2: SWAP idx=%d lhs=%d rhs=%d\n",idx,lhs,rhs);
            arr[idx] = rhs;
            arr[lhs] = lhs;
            swapflg = 1;
        }
    }

    dbg("swap2: EXIT swapflg=%d\n",swapflg);

    return swapflg;
}

// negfill -- scan for values that match index and do -1 replacement
int
negfill(int *arr,int len)
{
    int idx;
    int val;
    int negcnt = NEG;

    dbg("negfill: ENTER\n");

    // look for cells where value matches index (e.g. arr[2] == 2)
    for (idx = 0;  idx < len;  ++idx) {
        val = arr[idx];
        if (val != idx)
            continue;

        if (--negcnt < 0)
            continue;

        // fill the bad cell with -1
        dbg("negfill: NEGFIX idx=%d val=%d\n",idx,val);
        arr[idx] = -1;
    }

    // fill remaining values with -1
    for (;  negcnt > 0;  --negcnt) {
        while (1) {
            idx = rand() % len;
            val = arr[idx];
            if (val >= 0)
                break;
        }

        dbg("negfill: NEGFILL idx=%d\n",idx);
        arr[idx] = -1;
    }

    dbg("negfill: EXIT negcnt=%d\n",negcnt);

    return (negcnt >= 0);
}

// fillarray -- fill array satisfying all contraints
void
fillarray(int *arr,int len)
{

    while (1) {
        // get randomized list
        fillrand(arr,len);

        if (opt_v)
            prtarray(arr,len);

        // swap elements that are (e.g. arr[i] == arr[arr[i]])
        while (1) {
            if (! swap2(arr,len))
                break;
        }

        // look for self referential values and do -1 fill -- stop on success
        if (negfill(arr,len))
            break;
    }
}

// checkarray -- check for contraint violations
// RETURNS: 0=okay
int
checkarray(int *arr,int len)
{
    int idx;
    int lhs;
    int rhs;
    int negcnt = 0;
    int swapflg = 0;

    dbg("checkarray: ENTER\n");

    if (opt_v)
        prtarray(arr,len);

    for (idx = 0;  idx < len;  ++idx) {
        lhs = arr[idx];
        if (lhs < 0) {
            ++negcnt;
            continue;
        }

        rhs = arr[lhs];

        if (rhs == idx) {
            printf("checkarray: PAIR idx=%d lhs=%d rhs=%d\n",idx,lhs,rhs);
            swapflg = 2;
        }

        if (lhs == idx) {
            printf("checkarray: SELF idx=%d lhs=%d\n",idx,lhs);
            swapflg = 1;
        }
    }

    if (negcnt != NEG) {
        printf("checkarray: NEGCNT negcnt=%d\n",negcnt);
        swapflg = 3;
    }

    dbg("checkarray: EXIT swapflg=%d\n",swapflg);

    return swapflg;
}

int
main(int argc,char **argv)
{
    char *cp;
    int *arr;

    --argc;
    ++argv;

    opt_T = 100;
    opt_N = 16;

    for (;  argc > 0;  --argc, ++argv) {
        cp = *argv;
        if (*cp != '-')
            break;

        switch (cp[1]) {
        case 'N':
            opt_N = (cp[2] != 0) ? atoi(cp + 2) : 32;
            break;

        case 'T':
            opt_T = (cp[2] != 0) ? atoi(cp + 2) : 10000;
            break;

        case 'v':
            opt_v = ! opt_v;
            break;
        }
    }

    arr = malloc(sizeof(int) * opt_N);

    for (int tstno = 1;  tstno <= opt_T;  ++tstno) {
        printf("\n");
        printf("tstno: %d\n",tstno);
        fillarray(arr,opt_N);
        if (checkarray(arr,opt_N))
            break;
        prtarray(arr,opt_N);
    }

    free(arr);

    return 0;
}

В fillrand нет смысла выбирать и idx, и val случайным образом. Один из них можно повторять последовательно, не влияя на распределение. А другой может быть выбран из пула оставшихся невыбранных значений (Фишер-Йейтс) вместо случайного выбора из всех значений и отклонения ранее выбранных значений, и это улучшит время выполнения.

Eric Postpischil 09.01.2019 16:00

Неясно, как метод выбора элементов, которые отображаются на себя или которые были в свопах, как элементы для получения значений -1, обеспечивает такое же распределение, как и равномерное распределение по всем возможным назначениям, соответствующим ограничениям, указанным в вопросе.

Eric Postpischil 09.01.2019 16:01

Меня смущает ваше описание. Для размещения N элементов в N позиций у меня есть решение.

Вопрос: Поместите N элементов в N позиций с ограничениями:

(1) arr[i] != i; 
(2) if arr[i] = j, then arr[j] != i

Решение: Для текущего элемента i(0 <= i < N)

(1) Find candidate position count
    (a) count = N - i
    (b) if arr[i] is empty              =>    count -= 1
        else if arr[arr[i]] is empty    =>    count -= 1
(2) Select a random position from candidates
    (a) relative_index = random() % count
        (Note: relative_index means the position index in candidates)
    (b) Find absolute_index by searching candidates
        a candidate index j satisfies following constrains
            <1> arr[j] is empy
            <2> j != i
            <3> j != arr[i] when arr[i] is not empty

Я считаю, что следующее генерирует решение ограничений с равномерным распределением по всем решениям, которые удовлетворяют ограничениям:

  • Поместите числа от 0 до 15 в пул A.
  • Поместите числа от 0 до 15 в группу B.
  • 12 раз вытяните число a из пула A и число b из пула B (в каждом случае случайное вытягивание с равномерным распределением и удаление выпавшего числа из его пула, чтобы оно не было выбрано позже). Назначают m[a] = b.
  • Для каждого из четырех номеров a, оставшихся в пуле A, присвойте m[a] = -1.
  • Для всех i от 0 до 15 (включительно) и всех j от i до 15 (включительно) проверьте, есть ли m[i] == j && m[j] == i (обратите внимание, что это тестирует как для свопов, так и для m[i] == i, поскольку он включает i == j). Если такой случай обнаружен, откажитесь от присвоений и повторите алгоритм сначала.

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

Также можно использовать один пул вместо двух и вместо этого выполнить некоторую перегруппировку, когда назначены элементы -1, но описанный выше алгоритм легче выразить.

Другие вопросы по теме