Назначение каждой возможной комбинации диапазона чисел переменным - PullRequest
0 голосов
/ 27 февраля 2020

Учитывая диапазон чисел (1-25), как я могу создать al oop, чтобы на каждой итерации я получал уникальный набор переменных.

Чтобы привести пример, если бы я делал это с 4 числами мои переменные будут: на l oop 1:

a = 1, b = 2, c = 3, d = 4,

на l oop 2:

a = 1, b = 2, c = 4, d = 3

et c.

Я пытаюсь выполнить итерацию по каждому возможному числу для каждой позиции (подумайте о судоку), поэтому в сетке 3x3: a = верхняя левая позиция, b = верхняя середина и т. д. c ...

, так похожая на судоку, у меня было бы условие (каждая строка = 65: a + b + c + d + e = 65)

, поэтому я хочу иметь al oop, где я могу присвоить все значения переменным:

for (something) {
   var topLeft = (determined from loop)
   var nextPosition = etc.

Мое решение в настоящее время выглядит так:


var numbers = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25];
var a,b,c,d,e,f,g,h,i,j,k,l,n,o,p,q,r,s,t,u,v,w,x,y;
var vars = [a,b,c,d,e,f,g,h,i,j,k,l,n,o,p,q,r,s,t,u,v,w,x,y];
var counter = 0;
var found = false;
while(found == false) {
for (var asdf = numbers, i = asdf.length; i--; ) {
    var random = asdf.splice(Math.floor(Math.random() * (i + 1)), 1)[0];
    vars[i] = random;
}
if (
    {a+b+c+d+e = 65,
    f+g+h+i+j = 65,
    k+l+1+n+o = 65,
    p+q+r+s+t = 65,
    u+v+w+x+y = 65,
    a+f+k+p+u = 65,
    b+g+l+q+v = 65,
    c+h+1+r+w = 65,
    d+i+n+s+x = 65,
    e+j+o+t+y = 65,
    u+q+1+i+e = 65,
    a+g+1+s+y = 65}
) {
    console.log(a,b,c,d,e,f,g,h,i,j,k,l,n,o,p,q,r,s,t,u,v,w,x,y);
    found = true;
}
counter++;
}

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

Ответы [ 2 ]

1 голос
/ 27 февраля 2020

Учитывая диапазон чисел (1-25), как я могу создать al oop, чтобы на каждой итерации я получал уникальный набор переменных.

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

function getArrayMutations(arr, perms = [], len = arr.length) {
  if (len === 1) perms.push(arr.slice(0))

  for (let i = 0; i < len; i++) {
    getArrayMutations(arr, perms, len - 1)

    len % 2 // parity dependent adjacent elements swap
      ? [arr[0], arr[len - 1]] = [arr[len - 1], arr[0]]
      : [arr[i], arr[len - 1]] = [arr[len - 1], arr[i]]
  }

  return perms
}
getArrayMutations([1, 2, 3])
> [ [ 1, 2, 3 ],
    [ 2, 1, 3 ],
    [ 3, 1, 2 ],
    [ 1, 3, 2 ],
    [ 2, 3, 1 ],
    [ 3, 2, 1 ] ]

Будьте осторожны! Перестановки факториальны , что означает, что они очень быстро растут.

P (n, k) =

Это означает, что если вы хотите переставить 25 чисел, вы рассматриваем 1.551121e+25 возможных комбинаций, попадающих на территорию, которую невозможно вычислить при жизни.

Я пытаюсь перебирать все возможные числа для каждой позиции (подумайте судоку) так в сетке 3x3: a = верхняя левая позиция, b = верхняя середина и т. д. c ...

Двумерные массивы (на самом деле просто списки списков) - отличный способ хранить данные матрицы, как это. Это принципиально не меняет математику, чтобы изменить представление из одного массива, но об этом может быть проще подумать. Я не уверен на 100%, хотите ли вы сетку 3х3 или сетку 5х5, но я буду считать 5х5, поскольку в вашем примере у вас 25 чисел. Вы можете легко изменить их следующим образом:

function reshapeArray(array, n=5) {
    let result = []
    let row = 0
    let col = 0
    for (let i = 0; i < array.length; i++) {
        if (col == 0) {
            result[row] = []
        }
        result[row][col] = array[i]
        col++
        if (col == n) {
            col = 0
            row++
        }
    }

    return result
}
reshapeArray([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25])
> [ [  1,  2,  3,  4,  5 ],
    [  6,  7,  8,  9, 10 ],
    [ 11, 12, 13, 14, 15 ],
    [ 16, 17, 18, 19, 20 ],
    [ 21, 22, 23, 24, 25 ] ]

так похоже на судоку, что у меня будет условие (каждая строка = 65: a + b + c + d + e = 65)

Теперь, когда у вас есть данные в итерируемом массиве, вы можете очень легко проверить это или любое другое ограничение. Например:

/**
 * Checks if a matrix (a 2-d array like the output from reshapeArray())
 * meets our criteria.
 */
function checkMatrix(matrix) {
    for (let row = 0; row < matrix.length; row++) {
        let rowSum = 0
        for (let col = 0; col < matrix[row].length; col++) {
            rowSum += matrix[row][col]
        }
        // The row sum does not equal 65, so this isn't the one!
        if (rowSum != 65) {
            return false
        }
    }
    // All the row sums equal 65
    return true
}

Если вы хотите добавить дополнительные правила (например, чтобы сумма столбцов равнялась 65), просто измените код, чтобы проверить это. Вы можете получить значение в любой точке матрицы, проиндексировав его matrix[row][col], поэтому matrix[0][0] - это верхний левый угол и т. Д. c.

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

Да, так и будет. Судоку - это проблема NP-Hard . Если вы раньше не видели классов сложности, это просто математически формальный способ сказать, что нет более умного решения, которое будет значительно быстрее, чем просто проверка каждого возможного решения. Эта гипотетическая проблема не совсем та же, поэтому она может быть возможной, но она имеет очень ощущение np-i sh.

В настоящее время ваше решение с псевдокодом будет выглядеть так:

let permutations = getPermutations() // You're going to need to change this part
                                     // because getting all the permutations
                                     // ahead of time will take too long.
                                     // Just picking random numbers each time is
                                     // not actually a terrible idea. Or, look at
                                     // generator functions (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators)
for (let permutation of permutations) {
    let matrix = reshapeArray(permutation)
    if (checkMatrix(matrix)) {
        console.log("Found it")
        console.log(matrix)
        break
    }
}

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

0 голосов
/ 27 февраля 2020

Не уверен, что вопрос на самом деле. Я бы сохранил диапазон в массиве:

function range(start, stop = null, upperCase = false){
  let b = start, e = stop, s = 'abcdefghijklmnopqrstuvwxyz', x;
  const a = [], z = s.split(''), Z = s.toUpperCase().split(''); 
  if(typeof b === 'string'){
    s = z.indexOf(b.toLowerCase()); 
    if(e === null){
      x = z.length;
    }
    else{
      x = z.indexOf(e.toLowerCase())+1;
    }
    if(upperCase){
      return Z.slice(s, x);
    }
    return z.slice(s, x);
  }
  else if(e === null){
    e = b; b = 1;
  }
  for(let i=b; i<=e; i++){
    a.push(i);
  }
  return a;
}
function permuCount(array){
  let c = 1;
  for(let i=0,n=1,l=array.length; i<l; i++,n++){
    c *= n;
  }
  return c;
}
function comboCount(array){
  let l = array.length;
  return Math.pow(l, l);
}
console.log(range(2, 23)); console.log(range(10)); console.log(range('d')); 
console.log(range('g', 'p')); console.log(range('c', 'j', true));
// here is where you'll have an issue
const testArray = range(0, 9);
console.log(permuCount(testArray));
console.log(comboCount(testArray));

Как видите, комбинаций слишком много. Кроме того, вы уже должны были видеть следующий пост: Перестановки в JavaScript?

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