Посчитайте, сколько последовательностей расстояний далеко от всех остальных


13

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

Позвольте Pбыть двоичной строкой длины nи Tбыть двоичной строкой длины 2n-1. Мы можем вычислить nрасстояния Хэмминга между подстрокой Pкаждой nдлины Tв порядке слева направо и поместить их в массив (или список).

Пример последовательности расстояний Хэмминга

Пусть P = 101и T = 01100. Последовательность расстояний Хэмминга, которую вы получаете от этой пары, такова 2,2,1.

Определение близости

Теперь давайте рассмотрим две такие последовательности расстояний Хэмминга. Скажи x = (0, 2, 2, 3, 0)и y = (2, 1, 4, 4, 2)как примеры. Мы говорим , что xи yв closeслучае y <= x <= 2*yили если x <= y <= 2*x. Здесь скалярное умножение и неравенство взяты поэлементно. То есть, для двух последовательностей Aи B, A <= B iff A[i] <= B[i]по всем показателям i.

Обратите внимание, что последовательности расстояний Хэмминга образуют частичный порядок при таком способе их сравнения. Другими словами, многие пары последовательностей не являются ни большими, ни равными, ни меньшими или равными друг другу. Например (1,2)и (2,1).

Таким образом, используя пример выше, (0, 2, 2, 3, 0) <= 2*(2, 1, 4, 4, 2) = (4, 2, 8, 8, 4)но (0, 2, 2, 3, 0)не больше, чем (2, 1, 4, 4, 2). Также (2, 1, 4, 4, 2)не меньше или равно 2*(0, 2, 2, 3, 0) = (0, 4, 4, 6, 0). В результате xи yне близко друг к другу.

задача

Для увеличения, nначиная с n=1, рассмотрим все возможные пары двоичных строк Pдлины nи Tдлины 2n-1. Есть 2^(n+2n-1)такие пары и, следовательно, много последовательностей расстояний Хэмминга. Однако многие из этих последовательностей будут идентичны. Задача состоит в том, чтобы найти размер наибольшего набора последовательностей расстояний Хэмминга, чтобы никакие две последовательности не были близки друг к другу.

Ваш код должен выводить одно число на значение n.

Гол

В общем, ваш счет - самый высокий показатель, который nваш код достигает на моей машине за 5 минут (но читайте дальше). Время для общего времени работы, а не время только для этого n.

Чтобы получить оценки за неоптимальные ответы, потому что найти оптимальные ответы, скорее всего, будет сложно, нам понадобится немного тонкая система подсчета очков. Ваша оценка - это наибольшее значение, nдля которого никто другой не опубликовал более правильный ответ для любого размера, который меньше этого. Например, если вы выводите данные, 2, 4, 21а кто-то другой выводит данные, 2, 5, 15вы получите оценку только 1за то, что у кого-то есть лучший ответ n = 2. Если вы выводите данные, 2, 5, 21вы получаете оценку 3независимо от того, что выводит кто-то еще, поскольку все эти ответы являются оптимальными. Очевидно, что если у вас есть все оптимальные ответы, вы получите балл за самый высокий nпост. Тем не менее, даже если ваш ответ не является оптимальным, вы все равно можете получить счет, если никто другой не сможет его побить.

Пример ответов и проработанный пример

(Эти ответы еще не проверены. Независимая проверка будет принята с благодарностью.)

Благодаря ETHproductions:

  • n = 1 дает 2.
  • n = 2 дает 5.
  • n = 3 дает 21.

Давайте посмотрим на n = 2более подробно. В этом случае полный список последовательностей расстояний Хэмминга (представленных здесь кортежами):

[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]

Мы видим, что (0,0)это не близко к любому другому кортежу. В самом деле , если мы возьмем (0, 0), (0, 1), (1, 0), (2, 1), (1,2)то ни один из этих кортежей не близки к какой - либо из других. Это дает оценку 5для n = 2.

Для n = 3полного списка различных последовательностей расстояний Хэмминга:

 [(0, 0, 0), (0, 0, 1), (0, 1, 1), (0, 1, 2), (0, 1, 3), (0, 2, 1), (0, 2, 2), (0, 2, 3), (0, 3, 0), (0, 3, 1), (1, 0, 0), (1, 0, 1), (1, 0, 2), (1, 1, 0), (1, 1, 1), (1, 1, 2), (1, 1, 3), (1, 2, 0), (1, 2, 1), (1, 2, 2), (1, 2, 3), (1, 3, 0), (1, 3, 1), (1, 3, 2), (2, 0, 1), (2, 0, 2), (2, 0, 3), (2, 1, 0), (2, 1, 1), (2, 1, 2), (2, 1, 3), (2, 2, 0), (2, 2, 1), (2, 2, 2), (2, 2, 3), (2, 3, 1), (2, 3, 2), (2, 3, 3), (3, 0, 2), (3, 0, 3), (3, 1, 0), (3, 1, 1), (3, 1, 2), (3, 2, 0), (3, 2, 1), (3, 2, 2), (3, 3, 2), (3, 3, 3)]

Из этих 48последовательностей мы можем выбрать набор размеров, 21чтобы ни одна пара в этом наборе не была близка друг к другу.

Языки и библиотеки

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

Моя машина Время будет работать на моей 64-битной машине. Это стандартная установка Ubuntu с 8 ГБ ОЗУ, восьмиъядерным процессором AMD FX-8350 и Radeon HD 4250. Это также означает, что мне нужно иметь возможность запускать ваш код.

Ведущий ответ

  • Счет 4 за 2, 5, 21, 83, 361 Кристиана Сиверса. C ++
  • Оценка 5 за 2, 5, 21, 83, 372 по fəˈnɛtɪk. Javascript

Посмотрев на ваш вопрос, он показывает некоторые сходства со шпионами, пересмотренными на хакерранке, что является NP-полной проблемой
fəˈnɛtɪk

@ fəˈnɛtɪk Отлично! Обратите внимание, что мой вопрос не требует оптимальных решений, чтобы получить хорошую оценку.

@ fəˈnɛtɪk Можете ли вы также подтвердить ответы на 1,2,3 в вопросе?

@ fəˈnɛtɪk Я очень сомневаюсь, что это NP-хард. Вам придется закодировать Set Packing или другую NP-полную задачу в одно целое число только с полиномиальным изменением размера задачи.

297 уникальных массивов Хэмминга на 4, 2040 уникальных массивов на 5
fəˈnɛtɪk

Ответы:


5

C ++ с использованием библиотеки igraph

Спасибо за прекрасную возможность выучить новую библиотеку!

Эта программа теперь вычисляется 2, 5, 21, 83, 361быстро. Вы можете контролировать печать узлов с PRINTNODESконстантой.

Используемый граф имеет дополнительные ребра между узлами, соответствующими векторам расстояния, где один из них близок (но не равен) другому, а другой перевернут. Это ускоряет вычисления, и любой найденный независимый набор, конечно, также является одним из исходных графов. Кроме того, даже если он не полностью реализован, вычисленный независимый набор закрывается при обращении. Я считаю, что всегда существует максимальный независимый набор с этим свойством. По крайней мере, есть один для n<=4. (Я уверен, что могу показать 83 оптимально.)

#include<iostream>
#include<vector>
#include<set>
#include<algorithm>
#include<igraph.h>

using vect = std::vector<int>;

constexpr int MAXDIRECT=100;
constexpr int PRINTNODES=1;

std::set<int> avoid{};
igraph_t graph;
std::vector<vect> distance_vectors{};
int count;

int close_h(const vect &a, const vect &b ){
  // check one direction of the closeness condition
  for(auto i=a.begin(), j=b.begin(); i!=a.end(); i++,j++)
    if ( (*i > *j) || (*j > 2 * *i))
      return 0;
  return 1;
}

int close(const vect &a, const vect &b ){
  return close_h(a,b) || close_h(b,a);
}

vect distances(int n, int p, int t){
  vect res{};
  for (int i=0; i<n; ++i){
    int count = 0;
    for (int j=0; j<n; ++j)
      count += 1 & ((p>>j)^(t>>j));
    res.push_back(count);
    t >>= 1;
  }
  return res;
}

void print_vect( vect &v ){
  std::cout << "(";
  auto i=v.begin();
  std::cout << *i++;
  for( ; i!=v.end(); ++i)
    std::cout << "," << *i ;
  std::cout << ")\n";
}

void use_node( int n ){
  if(PRINTNODES)
    print_vect( distance_vectors[n] );
  ++count;
  avoid.insert( n );
  igraph_vector_t neighs;
  igraph_vector_init( &neighs, 0 );
  igraph_neighbors( &graph , &neighs, n, IGRAPH_OUT );
  for(int i=0; i<igraph_vector_size( &neighs ); ++i)
    avoid.insert( VECTOR(neighs)[i] );
  igraph_vector_destroy( &neighs );
}

void construct(int n){
  std::set<vect> dist_vects;
  for(int p=0; p>>n == 0; ++p)
    for(int t=0; t>>(2*n-2) == 0; ++t)   // sic! (because 0/1-symmetry)
      dist_vects.insert(distances(n,p,t));
  int nodes = dist_vects.size();
  std::cout << "distinct distance vectors: " << nodes << "\n";

  distance_vectors.clear();
  distance_vectors.reserve(nodes);
  std::copy(dist_vects.begin(), dist_vects.end(),
            back_inserter(distance_vectors));

  igraph_vector_t edges;
  igraph_vector_init( &edges, 0 );
  igraph_vector_t reversed;
  igraph_vector_init_seq( &reversed, 0, nodes-1 );
  for (int i=0; i<nodes-1; ++i){
    vect &x = distance_vectors[i];
    vect xr ( x.rbegin(), x.rend() );
    for(int j=i+1; j<nodes; ++j){
      vect &y = distance_vectors[j];
      if( xr==y ){
        VECTOR(reversed)[i] = j;
        VECTOR(reversed)[j] = i;
      }else if( close( x, y ) || close( xr, y) ){
        igraph_vector_push_back(&edges,i);
        igraph_vector_push_back(&edges,j);
      }
    }
  }
  std::cout << "edges: " << igraph_vector_size(&edges)/2 << "\n";

  igraph_create( &graph, &edges, nodes, IGRAPH_UNDIRECTED);
  igraph_vector_destroy( &edges );

  igraph_cattribute_VAN_setv( &graph, "r", &reversed );
  igraph_vector_destroy( &reversed );

  igraph_vector_t names;
  igraph_vector_init_seq( &names, 0, nodes-1 );
  igraph_cattribute_VAN_setv( &graph, "n", &names );
  igraph_vector_destroy( &names );

}

void max_independent( igraph_t *g ){
  igraph_vector_ptr_t livs;
  igraph_vector_ptr_init( &livs , 0 );
  igraph_largest_independent_vertex_sets( g, &livs );

  igraph_vector_t *nodes = (igraph_vector_t *) VECTOR(livs)[0];
  igraph_vector_t names;
  igraph_vector_init( &names, 0 );
  igraph_cattribute_VANV( g, "n", igraph_vss_vector( nodes ), &names );

  for(int i=0; i<igraph_vector_size(&names); ++i)
    use_node( VECTOR(names)[i] );
  igraph_vector_destroy( &names );
  igraph_vector_ptr_destroy_all( &livs );
}

void independent_comp( igraph_t *g );

void independent( igraph_t *g ){
  if(igraph_vcount( g ) < MAXDIRECT){
    max_independent( g );
    return;
  }
  igraph_vector_ptr_t components;
  igraph_vector_ptr_init( &components, 0 );
  igraph_decompose( g, &components, IGRAPH_WEAK, -1, 1);
  for(int i=0; i<igraph_vector_ptr_size( &components ); ++i)
    independent_comp( (igraph_t *) VECTOR(components)[i] );
  igraph_decompose_destroy( &components );
}

void independent_comp( igraph_t *g ){
  if (igraph_vcount( g ) < MAXDIRECT){
    max_independent( g );
    return;
  }
  igraph_vector_t degs;
  igraph_vector_init( &degs, 0 );
  igraph_degree( g, &degs, igraph_vss_all(), IGRAPH_OUT, 1 );
  int maxpos = igraph_vector_which_max( &degs );
  igraph_vector_destroy( &degs );  

  int name = igraph_cattribute_VAN( g, "n", maxpos );
  int revname = igraph_cattribute_VAN( g, "r", maxpos );
  int rev = -1;
  if(name!=revname){
    igraph_vector_ptr_t reversed_candidates_singleton;
    igraph_vector_ptr_init( &reversed_candidates_singleton, 0 );
    igraph_neighborhood( g, &reversed_candidates_singleton,
                         igraph_vss_1(maxpos), 2, IGRAPH_OUT );
    igraph_vector_t * reversed_candidates =
      (igraph_vector_t *) VECTOR(reversed_candidates_singleton)[0];
    igraph_vector_t names;
    igraph_vector_init( &names, 0 );
    igraph_cattribute_VANV( g, "n", igraph_vss_vector( reversed_candidates ),
                        &names );
    long int pos;
    igraph_vector_search( &names, 0, revname, &pos );
    rev = VECTOR(*reversed_candidates)[pos];
    igraph_vector_destroy( &names );
    igraph_vector_ptr_destroy( &reversed_candidates_singleton );
  }
  igraph_vs_t delnodes;
  igraph_vs_vector_small( &delnodes, maxpos, rev, -1 );
  igraph_delete_vertices( g, delnodes );
  igraph_vs_destroy( &delnodes );

  independent( g );
}

void handle(int n){
  std::cout << "n=" << n << "\n";
  avoid.clear();
  count = 0;
  construct( n );
  independent( &graph );
  // try all nodes again:
  for(int node=0; node<igraph_vcount( &graph ); ++node)
    if(avoid.count(node)==0)
      use_node(node);
  std::cout << "result: " << count << "\n\n";
  igraph_destroy( &graph );
}

int main(){
  igraph_i_set_attribute_table( &igraph_cattribute_table );
  for(int i=1; i<6; ++i)
    handle(i);
}

Чтобы скомпилировать на Debian, установите libigraph0-devи сделайте g++ -std=c++11 -Wall -O3 -I/usr/include/igraph -o ig ig.cpp -ligraph.

Старое описание:

Библиотека igraph имеет функцию для вычисления максимального размера независимого набора вершин графа. Он может решить эту проблему n=3менее чем за секунду и не заканчивается в течение нескольких дней n=4.

Поэтому я делаю граф на связанные компоненты и позволяю библиотеке обрабатывать небольшие (меньше, чем MAXDIRECTузлы) компоненты. Для других компонентов я выбираю вершину и удаляю ее. В лучшем случае это разбивает график на несколько компонентов, но обычно это не так. В любом случае, компоненты (возможно, только один) меньше, и мы можем использовать рекурсию.

Очевидно, что выбор вершины важен. Я просто беру один из максимальной степени. Я обнаружил, что получаю лучший результат (но только для n=4), когда использую перевернутый список узлов. Это объясняет волшебную часть constructфункции.

Возможно, стоит улучшить выбор. Но кажется более важным пересмотреть удаленные узлы. Прямо сейчас я никогда не смотрю на них снова. Некоторые из них могут быть не связаны ни с одним из выбранных узлов. Проблема в том, что я не знаю, какие узлы образуют независимое множество. Например, удаление узлов перенумеровывает остальные узлы. Это можно сделать, прикрепив к ним атрибуты. Но что еще хуже, вычисление числа независимости просто дает это число. Лучшая альтернатива, предлагаемая библиотекой, состоит в том, чтобы вычислять все самые большие независимые наборы, что медленнее (насколько кажется, зависит от размера графика). Тем не менее, это, кажется, прямой путь. Гораздо более расплывчато, я также думаю, что было бы полезно рассмотреть, можем ли мы использовать особый способ определения графа.

Случай n=6может стать достижимым (вообще, не обязательно через 5 минут), если я заменю рекурсию циклом, используя очередь для остальных компонентов.

Мне было интересно взглянуть на компоненты графиков. Ведь n=4их размеры есть 168, 2*29, 2*28, 3, 4*2, 4*1. Только самый большой не может быть обработан напрямую.

Для n=5, этих размеров 1376, 2*128, 2*120, 119, several <=6.

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

Поскольку n=6самый большой компонент содержит 11941узлы (из общего числа 15425), следующие два самых больших компонента имеют размер 596.

Ибо n=7эти цифры есть 107593 (125232), 2647.


Не могли бы вы дать мне знать, что такое набор для 83, я хочу знать, почему мой алгоритм не достигает такого высокого значения для 4, а как-то становится выше для 5: P
fəˈnɛtɪk

Это должно быть g++ -std=c++11 -Wall -O3 -I/usr/include/igraph -o sievers sievers.cpp -ligraph. Это важно где -ligraphесть.

@ChristianSievers Как генерация ребер работает в коде?
fəˈnɛtɪk

@ChristianSievers Мне было интересно, как он определяет, с чем должна соединяться каждая вершина. Обращение массива могло бы испортить это.
fəˈnɛtɪk

@ fəˈnɛtɪk Векторы расстояний, похоже, выбраны из того, что setя использую, чтобы избежать дубликатов, но я даже не думал об их порядке, когда писал этот код. Внутренний цикл, начинающийся с « i+1просто», избегает смотреть на пару, а также на ее замененную версию, которая не нужна и является самым простым способом избежать петель (ребер (a,a)). Это не зависит от порядка, в котором приходят узлы, мне все равно, получу я (a,b)или (b,a).
Кристиан Сиверс

3

Javascript, Seq: 2,5,21, 81 83,372 67,349

Удалось увеличить значение на 4 с помощью случайного удаления элементов в начале моего поиска. Как ни странно, удаление 20 элементов с более чем 6 соединениями было быстрее, чем удаление 5 элементов с более чем 8 соединениями ...

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

Код:

input=4;
maxConnections=6;
numRand=20;

hammings=[];
h=(x,y)=>{retVal=0;while(x||y){if(x%2!=y%2)retVal++;x>>=1;y>>=1}return retVal};
for(i=1<<(input-1);i<1<<input;i++){
  for(j=0;j<1<<(2*input);j++){
    hamming=[];
    for(k=0;k<input;k++){
      hamming.push(h((j>>k)%(1<<input),i));
    }
    equal=0;
    for(k=0;k<hammings.length;k++){
      if(hamming.join("")==hammings[k].join("")){
        equal=1;
        break;
      }
    }
    if(!equal)hammings.push(hamming);
  }
}
adjMat=[];
for(i=0;i<Math.pow(input+1,input);i++){
  row=[];
  for(j=0;j<Math.pow(input+1,input);j++){
    row.push(0);
  }
  adjMat.push(row);
}
nodes=[]
for(i=0;i<Math.pow(input+1,input);i++){
  nodes[i]=0;
}
for(i=0;i<hammings.length;i++){
  sum=0;
  chkNodes=[[]];
  for(j=0;j<input;j++){
    chkVal=[];
    t=Math.pow(input+1,j);
    sum+=t*hammings[i][j];
    tmp=[];
    for(r=0;r<chkNodes.length;r++){
      for(k=hammings[i][j];k<=Math.min(hammings[i][j]*2,input);k++){
        stor=[]
        for(s=0;s<chkNodes[r].length;s++){
          stor.push(chkNodes[r][s])
        }
        stor.push(k)
        tmp.push(stor);
      }
    }
    chkNodes=[];
    for(r=0;r<tmp.length;r++){
      chkNodes.push(tmp[r])
    }
  }
  nodes[sum]=1;
  for(j=0;j<chkNodes.length;j++){
    adjSum=0
    for(k=0;k<input;k++){
      adjSum+=Math.pow(input+1,k)*chkNodes[j][k]
    }
    if(adjSum!=sum)adjMat[sum][adjSum]=adjMat[adjSum][sum]=1
  }
}
t=nodes.length;
for(i=0;i<t;i++){
  if(!nodes[i]){
    for(k=0;k<t;k++){
      adjMat[i][k]=adjMat[k][i]=0
    }
  }
}
sum=(a,b)=>a+b;
console.log(nodes.reduce(sum))
connections=x=>x.reduce(sum)
counts=adjMat.map(connections);
stor=[];
for(i=0;i<t;i++){
  stor.push(nodes[i]);
}
maxRemainder=0;

greater=[]
for(i=0;i<t;i++){
  if(nodes[i]&&counts[i]>maxConnections){
    greater.push(i);
  }
}

if(input==4){
  for(w=0;w<greater.length*numRand;w++){
    for(i=0;i<t;i++){
      nodes[i]=stor[i];
    }
    counts=adjMat.map(connections);
    toRemove=Math.floor(Math.random()*numRand*2)
    for(i=0;i<toRemove&&i<greater.length;i++){
      rand=Math.floor(Math.random()*greater.length);
      if(nodes[greater[rand]]){
        nodes[greater[rand]]=0;
        for(j=0;j<t;j++){
          if(adjMat[rand][j]){
            counts[j]--;
          }
        }
      }
    }

    for(i=0;i<t*t;i++){
      max=0;
      maxLoc=0;
      for(j=0;j<t;j++){
        if(counts[j]>=max&&nodes[j]){
          max=counts[j];
          maxLoc=j;
        }
      }
      if(max>0){
        for(j=0;j<t;j++){
          if(adjMat[maxLoc][j]){
            counts[j]--;
            if(counts[j]<max-1&&stor[j]&&!nodes[j]){
              nodes[j]=1;
              for(k=0;k<t;k++){
                if(adjMat[j][k])counts[k]++;
              }
            }
          }
          nodes[maxLoc]=0;
        }
      }
      else{
        break;
      }
    }
    maxRemainder=Math.max(maxRemainder,nodes.reduce(sum))
    //console.log(nodes.reduce(sum));
  }
  console.log(maxRemainder);
}
else{
  for(i=0;i<t*t;i++){
    max=0;
    maxLoc=0;
    for(j=0;j<t;j++){
      if(counts[j]>=max&&nodes[j]){
        max=counts[j];
        maxLoc=j;
      }
    }
    if(max>0){
      for(j=0;j<t;j++){
        if(adjMat[maxLoc][j]){
          counts[j]--;
          if(counts[j]<max-1&&stor[j]&&!nodes[j]){
            nodes[j]=1;
            for(k=0;k<t;k++){
              if(adjMat[j][k])counts[k]++;
            }
          }
        }
        nodes[maxLoc]=0;
      }
    }
    else{
      break;
    }
  }
  console.log(nodes.reduce(sum));
}

Попробуйте онлайн!

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

for(i=0;i<t;i++){
  if(nodes[i]){
    tmp=[]
    for(j=0;j<input;j++){
      tmp.unshift(Math.floor(i/Math.pow(input+1,j))%(input+1))
    }
    console.log(tmp.join(""))
    output=""
    for(j=0;j<t;j++){
      if(adjMat[i][j]&&stor[j]){
        outArr=[]
        for(k=0;k<input;k++){
          outArr.unshift(Math.floor(j/Math.pow(input+1,k))%(input+1))
        }
        output+=" "+outArr.join("");
      }
    }
    console.log(output)
  }
}

Объяснение:

Во-первых, код генерирует все уникальные расстояния Хемминга от подстрок.

input=3;
hammings=[];
h=(x,y)=>{retVal=0;while(x||y){if(x%2!=y%2)retVal++;x>>=1;y>>=1}return retVal};
for(i=1<<(input-1);i<1<<input;i++){
  for(j=0;j<1<<(2*input);j++){
    hamming=[];
    for(k=0;k<input;k++){
      hamming.push(h((j>>k)%(1<<input),i));
    }
    equal=0;
    for(k=0;k<hammings.length;k++){
      if(hamming.join("")==hammings[k].join("")){
        equal=1;
        break;
      }
    }
    if(!equal)hammings.push(hamming);
  }
}

Далее код преобразует этот список в неориентированный граф

adjMat=[];
for(i=0;i<Math.pow(input+1,input);i++){
  row=[];
  for(j=0;j<Math.pow(input+1,input);j++){
    row.push(0);
  }
  adjMat.push(row);
}
nodes=[]
for(i=0;i<Math.pow(input+1,input);i++){
  nodes[i]=0;
}
for(i=0;i<hammings.length;i++){
  sum=0;
  chkNodes=[[]];
  for(j=0;j<input;j++){
    chkVal=[];
    t=Math.pow(input+1,j);
    sum+=t*hammings[i][j];
    tmp=[];
    for(r=0;r<chkNodes.length;r++){
      for(k=hammings[i][j];k<=Math.min(hammings[i][j]*2,input);k++){
        stor=[]
        for(s=0;s<chkNodes[r].length;s++){
          stor.push(chkNodes[r][s])
        }
        stor.push(k)
        tmp.push(stor);
      }
    }
    chkNodes=[];
    for(r=0;r<tmp.length;r++){
      chkNodes.push(tmp[r])
    }
  }
  nodes[sum]=1;
  for(j=0;j<chkNodes.length;j++){
    adjSum=0
    for(k=0;k<input;k++){
      adjSum+=Math.pow(input+1,k)*chkNodes[j][k]
    }
    if(adjSum!=sum)adjMat[sum][adjSum]=adjMat[adjSum][sum]=1
  }
}

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

t=nodes.length;
for(i=0;i<t;i++){
  if(!nodes[i]){
    for(k=0;k<t;k++){
      adjMat[i][k]=adjMat[k][i]=0
    }
  }
}
sum=(a,b)=>a+b;
counts=adjMat.map(x=>x.reduce(sum));
stor=[];
for(i=0;i<t;i++){
  stor.push(nodes[i]);
}
for(i=0;i<t*t;i++){
  max=0;
  maxLoc=0;
  for(j=0;j<t;j++){
    if(counts[j]>=max&&nodes[j]){
      max=counts[j];
      maxLoc=j;
    }
  }
  if(max>0){
    for(j=0;j<t;j++){
      if(adjMat[maxLoc][j]){
        counts[j]--;
        if(counts[j]<max-1&&stor[j]&&!nodes[j]){
          nodes[j]=1;
          for(k=0;k<t;k++){
            if(adjMat[j][k])counts[k]++;
          }
        }
      }
      nodes[maxLoc]=0;
    }
  }
  else{
    break;
  }
}
console.log(nodes.reduce(sum));

Наборы:

1:

0 1

2:

00 01 10 12 21

3:

000 001 011 013 030 031 100 101 110 111 123 130 132 203 213 231 302 310 312 
321 333

4:

0000 0001 0011 0111 0124 0133 0223 0230 0232 0241 0313 0320 0322 0331 0403 
0412 1000 1001 1013 1021 1100 1102 1110 1111 1134 1201 1224 1233 1243 1304 
1314 1323 1330 1332 1342 1403 1413 1420 1422 2011 2033 2124 2133 2140 2142 
2214 2230 2241 2303 2313 2320 2331 2411 3023 3032 3040 3041 3101 3114 3123 
3130 3132 3141 3203 3213 3220 3231 3302 3310 3312 3321 3334 3343 3433 4031 
4113 4122 4131 4210 4212 4221 4311 4333

5:

00000 00001 00011 00111 00123 01112 01235 01244 01324 01343 02111 02230 
02234 02333 02342 02432 02441 02522 02530 02531 03134 03142 03220 03224 
03233 03241 03314 03323 03331 03403 03412 03421 03520 04133 04141 04214 
04223 04232 04303 04313 04322 05042 05050 05051 05132 10000 10001 10011 
10122 10212 10221 10245 11000 11001 11013 11022 11100 11112 11120 11121 
11202 11211 11345 11353 11443 12012 12111 12201 12245 12253 12335 12344 
12352 12425 12430 12434 12442 12513 12532 13033 13042 13244 13252 13325 
13330 13334 13342 13404 13424 13433 13441 13520 13522 13531 14032 14051 
14140 14152 14225 14230 14234 14241 14243 14304 14315 14324 14332 14413 
14420 14422 14431 15041 15050 15125 15133 15142 15215 15223 15232 20112 
20135 20211 20253 20334 20352 21012 21021 21102 21110 21111 21201 21245 
21344 21352 21430 21433 21442 21514 21523 22011 22101 22135 22244 22252 
22325 22334 22340 22343 22405 22415 22424 22441 22520 22522 22531 23041 
23144 23150 23152 23225 23234 23240 23243 23251 23304 23315 23324 23333 
23341 23403 23413 23420 23432 23521 24031 24050 24125 24130 24134 24142 
24151 24215 24224 24233 24303 24314 24320 24323 24331 24412 24421 25123 
25132 25141 25203 25214 25222 25231 25302 25312 25321 30234 30243 30252 
30324 30333 30340 30342 30414 30423 30430 30432 31011 31235 31244 31253 
31325 31334 31340 31343 31405 31415 31424 31432 31441 31504 31521 32025 
32034 32100 32144 32152 32225 32234 32240 32243 32251 32304 32315 32324 
32330 32333 32342 32403 32414 32423 32512 33024 33031 33033 33125 33134 
33140 33143 33151 33215 33224 33230 33233 33242 33303 33314 33320 33323 
33332 33412 33431 34124 34133 34203 34214 34223 34232 34241 34310 34313 
34322 34411 35202 35213 35221 35311 40323 40332 40341 40431 40505 40513 
41135 41144 41240 41243 41252 41324 41330 41333 41342 41403 41414 41423 
41512 42033 42134 42143 42230 42233 42242 42303 42310 42314 42323 42332 
42341 42413 42422 42431 43023 43124 43130 43133 43142 43203 43220 43223 
43232 43241 43302 43313 43322 43331 43421 44114 44123 44132 44210 44213 
44222 44231 44312 44321 50413 50422 50504 51233 51242 51251 51323 51332 
51341 51413 51422 52023 52133 52142 52151 52223 52232 52241 52313 52322 
52331 52421 53102 53114 53122 53210 53213 53321 54201 54212 54221 54311

Спасибо за первый ответ! Не могли бы вы дать пошаговое руководство для идиотов о том, как запустить ваш код в Linux, пожалуйста?

Может быть, fəˈnɛtɪk сможет превратить свой код в фрагмент стека?
mbomb007

@ mbomb007 по некоторым причинам, превращение этого во фрагмент кода приводит к тому, что ошибка 0 не является функцией ... в строке для (j = 0; j <t; j ++)
fəˈnɛtɪk

Может быть, вы могли бы попробовать JSFiddle?
mbomb007

Если у вас есть Chrome, вы можете скопировать, вставить код в консоль и запустить его, нажав Enter. Не совсем уверен насчет других браузеров. Chrome запускает код быстрее, чем онлайн-системы для меня.
Удалось
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.