У меня есть задача, в которой я должен заполнить массив 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;
}
}
}
}
}
можешь показать нам свой код? с головы до ног я бы использовал 2 массива aux, чтобы помочь с первыми двумя условиями
Я знаю, я просто не знаю, как это преобразовать в код .. Слишком много «раз» и «если», и мне трудно справиться с этим, лол
Просто заполните массив нужными значениями, но сделайте случайный перестановки
тем не менее, если показать нам, что вы сделали, мы сможем понять, в чем проблема в вашем коде.
@ H.cohen Слишком долго, чтобы вставлять его сюда: \
Что ж, тогда я добавлю две части: 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 ++; }}
Вопрос из заголовка называется "перемешать". А вот для этого алгоритм Фишер-Йейтс. Однако другие условия являются дополнительными, что потребует дополнительных разъяснений.
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; }}}}}
@ סמיזלדין Пожалуйста, удалите эти комментарии и внесите их в свой вопрос как отредактированный.
Пожалуйста, редактировать свой вопрос и поместите свой код в блок кода, а не добавляйте его в качестве комментария.
Также поясните, что вы имеете в виду под значениями -1. Если вы заполняете массив 16 случайными значениями в диапазоне 0-15, куда вы хотите поместить значения -1?
@CraigEstey поехали
@CraigEstey Случайные места, неважно где. четыре элемента должны быть -1, а все остальные двенадцать должны быть в диапазоне 0-15.
определяется ли N 16 и определяется ли C 12?
@ H.cohen, нет, N - 16 и C. Я использую C для заполнения 4 случайных элементов в -1, а затем использую N для просмотра всех элементов и помещаю случайные числа 0-15 только в те, которые не заполнены -1.
Пожалуйста, предоставьте всю информацию по вашему вопросу. Желательно также превратить его в минимальный воспроизводимый пример.
вы можете жадно инициализировать массив, а затем применить случайные перестановки в массиве, чтобы рандомизировать его, при этом следуя правилам, которые вы должны соблюдать
@EugeneSh. Я пробовал и понятия не имею, почему не работает? Я выложил это в пост
Состояние (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.
О создании неисправностей см. В этих вопросах Переполнение стека и Обмен стеком. Последнее указывает на безотказный алгоритм.
Какое распределение вероятностей вы хотите? Должны ли все возможности, удовлетворяющие ограничениям, быть одинаково вероятными?





Надеюсь, это поможет, я старался придерживаться вашего первого черновика и того, к чему вы стремились, просто чтобы отметить, что это должно работать для массива длиной 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
Хорошо, я вижу, что цикл не возникает, потому что вы сначала помещаете четыре элемента -1 и увеличиваете full, поэтому при назначении последнего одного или двух элементов в пуле всегда остается пять или шесть значений, соответственно. (Я должен подумать, как это повлияет на распределение вероятностей.) Вам следует переименовать full и изменить его описание (которое гласит: «Полный - это когда все индексы заполнены»). Это звучит как логическое значение, но на самом деле это количество уже заполненных чисел.
Я думаю, что Полон более логический, но я подумаю над этим. tnx для вашего ввода =) @EricPostpischil
Думаю на раздачу сказывается. Рассмотрим алгоритм, примененный к 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 = ⅓.)
какой тип распределения, по вашему мнению, предназначен для ОП? ограничения представленного алгоритма влияют на «случайность» выходных данных, но то, распределяются ли -1 случайные индексы первым-последним или между ними, не должно изменять вероятность каждого результата. Я не уверен, что понял, что вы имели в виду в своем примере. @EricPostpischil
Математики используют термин «случайный» в техническом смысле для обозначения переменной с возможными значениями, которые являются результатами некоторого случайного процесса, который может иметь разные распределения. Нетехнические пользователи часто используют слово «случайный», чтобы включить равномерное распределение. Есть три возможности: (a) OP предполагал равномерное распределение, которого этот ответ не обеспечивает. (b) OP предполагал какое-то конкретное распределение, о котором не было сказано, и поэтому нет оснований полагать, что распределение, полученное с помощью этого ответа, соответствует ему. (c) OP не намеревалась какого-либо конкретного распространения, и в этом случае…
… Любое решение является удовлетворительным, включая подпрограмму, которая всегда возвращает [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, -1, -1, -1, -1], поскольку это результат извлечения из распределения с вероятностью 1 для этого результата и 0 для других. Я думаю, что (а) наиболее вероятно, но, если это (б), вопрос необходимо прояснить.
Мой 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). В противном случае, как вы упомянули, отклоните решение и повторите попытку.
Исключение элементов, которые сопоставляются сами с собой, путем их замены соседом, сгенерирует более высокую вероятность m[i+1] == i, чем при равномерном распределении.
Неясно, что генерация полного присваивания, удовлетворяющего условиям, исключающим −1 элементов, а затем замена некоторых элементов на −1 порождает равномерное распределение по решениям, удовлетворяющим всем условиям. Я думаю, что это может не одобрить решения, в которых назначения содержали бы элемент подкачки или самокопирования, который скрыт элементами -1.
@EricPostpischil Равномерность никогда не указывалась в качестве требования. Элементы, которые сопоставляются друг с другом, охватываются моим последним утверждением - проверьте его, отклоните и повторите попытку, если он найден.
@pjs: если единообразие не является требованием, тогда процедура, которая всегда возвращает [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, -1, -1, -1, −1] удовлетворяет вопросу, поскольку это просто распределение с вероятностью 1 для этого решения и 0 для остальных. В разговорной речи слово «случайный» часто означает однородный; наивные заказчики случайных выборок обычно подразумевают рисование с равномерным распределением. Если вы не уверены, что они предполагали равномерное распределение, вам следует запросить разъяснения. Конечно, какое бы распределение ни выпало из скомпонованного алгоритма, это не то, что было задумано.
@EricPostpischil Случайность не означает единообразия, она определяется отсутствием предсказуемости. Кажется, вы смешиваете случайность с энтропией. Это правда, что равномерное распределение имеет максимальную энтропию Шеннона, но я сомневаюсь, что вы осмелитесь заявить, что другие распределения, такие как гауссово, не являются случайными. Случайность - это все, что требовалось.
@pjs: Я не делал никаких заявлений о случайности или энтропии, за исключением того, что заявлял, что нетехнические ораторы часто просто просят «случайное», когда им нужна униформа. Это не утверждение о математике, а просто наблюдение за множеством примеров. Маловероятно, что простая случайность - это «все», что было желательно, и у них нет никаких ограничений на это, так как какой цели может служить какое-то сильно искаженное распределение, даже не зная об этом?
Я не уверен, что полностью, но я думаю, что следующее отвечает всем вашим особым ограничениям [надеюсь].
Функция случайного списка - это разновидность Фишера Йейтса. Вы можете перекодировать его, чтобы использовать 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 случайным образом. Один из них можно повторять последовательно, не влияя на распределение. А другой может быть выбран из пула оставшихся невыбранных значений (Фишер-Йейтс) вместо случайного выбора из всех значений и отклонения ранее выбранных значений, и это улучшит время выполнения.
Неясно, как метод выбора элементов, которые отображаются на себя или которые были в свопах, как элементы для получения значений -1, обеспечивает такое же распределение, как и равномерное распределение по всем возможным назначениям, соответствующим ограничениям, указанным в вопросе.
Меня смущает ваше описание. Для размещения 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
Я считаю, что следующее генерирует решение ограничений с равномерным распределением по всем решениям, которые удовлетворяют ограничениям:
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, но описанный выше алгоритм легче выразить.
Почему бы не продолжать генерировать числа, пока они не станут подходящими? Просто проверяйте каждый раз и попробуйте еще раз, если это не помогло.