Policz, ile sekwencji odległości jest dalekie od wszystkich innych

13

Odległość Hamminga pomiędzy dwa ciągi o równej długości jest numer pozycji, w którym odpowiednie symbole są różne.

Niech Pbędzie dwójkowym ciągiem długości ni Tdwójkowym ciągiem długości 2n-1. Możemy obliczyć nodległości Hamminga między podciągiem Pkażdej ndługości Tw kolejności od lewej do prawej i umieścić je w tablicy (lub liście).

Przykład sekwencji odległości Hamminga

Niech P = 101i T = 01100. Sekwencja odległości Hamminga uzyskana z tej pary to 2,2,1.

Definicja bliskości

Rozważmy teraz dwie takie sekwencje odległości Hamminga. Powiedz x = (0, 2, 2, 3, 0)i y = (2, 1, 4, 4, 2)jako przykłady. Mówimy to xi yjesteśmy, closejeśli y <= x <= 2*ylub jeśli x <= y <= 2*x. Tutaj mnożenie skalarne i nierówności są uwzględniane elementarnie. To znaczy, dla dwóch sekwencji Ai B, A <= B iff A[i] <= B[i]dla wszystkich indeksów i.

Zauważ, że sekwencje odległości Hamminga tworzą częściowy porządek w ten sposób ich porównywania. Innymi słowy, wiele par sekwencji nie jest ani większych, ani równych, ani mniejszych ani równych sobie. Na przykład (1,2)i (2,1).

Korzystając z powyższego przykładu, (0, 2, 2, 3, 0) <= 2*(2, 1, 4, 4, 2) = (4, 2, 8, 8, 4)ale (0, 2, 2, 3, 0)nie jest większy niż (2, 1, 4, 4, 2). Również (2, 1, 4, 4, 2)nie jest mniejszy ani równy 2*(0, 2, 2, 3, 0) = (0, 4, 4, 6, 0). W rezultacie xi ynie są blisko siebie.

Zadanie

Aby zwiększyć, nzaczynając od n=1, rozważ wszystkie możliwe pary ciągów binarnych Po długości ni Tdługości 2n-1. Istnieją 2^(n+2n-1)takie pary, a zatem wiele sekwencji odległości Hamminga. Jednak wiele z tych sekwencji będzie identycznych. Zadanie polega na znalezieniu rozmiaru największego zestawu sekwencji odległości Hamminga, aby żadne dwie sekwencje nie były blisko siebie.

Twój kod powinien wypisywać jedną liczbę na wartość n.

Wynik

Twój wynik jest ogólnie najwyższy, jaki nTwój kod osiąga na moim komputerze w ciągu 5 minut (ale czytaj dalej). Czas dotyczy całkowitego czasu działania, a nie tylko tego czasu n.

Aby uzyskać wyniki dla nieoptymalnych odpowiedzi, ponieważ znalezienie optymalnych odpowiedzi może być trudne, potrzebujemy nieco subtelnego systemu punktacji. Twój wynik jest najwyższą wartością, ndla której nikt inny nie opublikował wyższej poprawnej odpowiedzi dla dowolnego rozmiaru, który jest mniejszy niż równy. Na przykład, jeśli wyprowadzasz dane wyjściowe, 2, 4, 21a ktoś inny wyświetla dane wyjściowe, 2, 5, 15uzyskasz wynik tylko wtedy, 1gdy ktoś inny ma lepszą odpowiedź n = 2. Jeśli wypiszesz wynik, 2, 5, 21uzyskasz wynik 3bez względu na to, co ktoś wypisze, ponieważ wszystkie te odpowiedzi są optymalne. Oczywiście, jeśli masz wszystkie optymalne odpowiedzi, otrzymasz wynik za najwyższą, nktórą opublikujesz. Jednak nawet jeśli twoja odpowiedź nie jest optymalna, nadal możesz uzyskać wynik, jeśli nikt inny go nie pokona.

Przykładowe odpowiedzi i działający przykład

(Te odpowiedzi są jeszcze niezaznaczone. Niezależna weryfikacja byłaby wdzięczna).

Dzięki ETHproductions:

  • n = 1 daje 2.
  • n = 2 daje 5.
  • n = 3 daje 21.

Spójrzmy n = 2bardziej szczegółowo. W tym przypadku pełna lista sekwencji odległości Hamminga (reprezentowana tutaj przez krotki) to:

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

Widzimy, że (0,0)nie jest to zbliżone do żadnej innej krotki. W rzeczywistości, jeśli weźmiemy (0, 0), (0, 1), (1, 0), (2, 1), (1,2)to żaden z tych krotek są zbliżone do żadnej z pozostałych. Daje to wynik 5dla n = 2.

Dla n = 3pełnej listy odrębnych sekwencji odległość Hamminga jest:

 [(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)]

Z tych 48sekwencji możemy wybrać zestaw wielkości 21, aby żadna para w tym zestawie nie była blisko siebie.

Języki i biblioteki

Możesz użyć dowolnego dostępnego języka i bibliotek, które ci się podobają. Tam, gdzie jest to wykonalne, dobrze byłoby móc uruchomić kod, więc proszę podać pełne wyjaśnienie, jak uruchomić / skompilować kod w systemie Linux, jeśli to w ogóle możliwe.

Moja maszyna Czasy zostaną uruchomione na moim komputerze 64-bitowym. Jest to standardowa instalacja ubuntu z 8 GB pamięci RAM, ośmiordzeniowym procesorem AMD FX-8350 i Radeon HD 4250. Oznacza to również, że muszę mieć możliwość uruchomienia kodu.

Wiodąca odpowiedź

  • Wynik 4 dla 2, 5, 21, 83, 361 autorstwa Christiana Sieversa. C ++
  • Ocena 5 dla 2, 5, 21, 83, 372 przez fəˈnɛtɪk. JavaScript

źródło
Po spojrzeniu na twoje pytanie, pokazuje pewne podobieństwa do szpiegów, poprawionych na hackerrank, co jest problemem NP-zupełnym
fəˈnɛtɪk
@ fəˈnɛtɪk Świetnie! Pamiętaj, że moje pytanie nie wymaga optymalnych rozwiązań, aby uzyskać dobry wynik.
@ fəˈnɛtɪk Czy możesz również potwierdzić odpowiedzi na 1,2,3 w pytaniu?
@ fəˈnɛtɪk Wątpię, czy to trudne NP. Będziesz musiał zakodować Set Packing lub inny problem NP-complete w pojedynczą liczbę całkowitą z jedynie wielomianową zmianą wielkości problemu.
297 unikalnych tablic Hamminga dla 4, 2040 unikalnych tablic
Hamminga

Odpowiedzi:

5

C ++ przy użyciu biblioteki igraph

Dziękujemy za miłą okazję do nauki nowej biblioteki!

Ten program oblicza teraz 2, 5, 21, 83, 361szybko. Możesz kontrolować drukowanie węzłów za pomocą PRINTNODESstałej.

Zastosowany wykres ma dodatkowe krawędzie między węzłami odpowiadające wektorom odległości, w których jeden jest blisko (ale nie równy) względem drugiego odwróconego. Przyspiesza to obliczenia, a każdy znaleziony niezależny zestaw jest oczywiście jednym z oryginalnych wykresów. Ponadto, nawet jeśli nie jest to w pełni wymuszone, obliczony niezależny zestaw jest zamykany podczas cofania. Wierzę, że zawsze istnieje maksymalny niezależny zestaw z tą właściwością. Przynajmniej jest jeden dla n<=4. (Jestem pewien, że mogę wykazać, że 83 jest optymalny.)

#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);
}

Aby skompilować na Debianie, zainstaluj libigraph0-devi wykonaj g++ -std=c++11 -Wall -O3 -I/usr/include/igraph -o ig ig.cpp -ligraph.

Stary opis:

Biblioteka igraph ma funkcję obliczania maksymalnego rozmiaru niezależnego zestawu wierzchołków wykresu. Potrafi poradzić sobie z tym problemem n=3w niecałą sekundę i nie wygasa za kilka dni n=4.

Więc to, co robię, to rozkładam wykres na połączone komponenty i pozwalam bibliotece obsługiwać małe MAXDIRECTkomponenty (mniejsze niż węzły). W przypadku innych komponentów wybieram wierzchołek i usuwam go. W najlepszym przypadku dzieli to wykres na kilka składników, ale zazwyczaj nie. W każdym razie komponenty (może tylko jeden) są mniejsze i możemy użyć rekurencji.

Oczywiście wybór wierzchołka jest ważny. Po prostu biorę jeden z maksymalnych stopni. Przekonałem się, że uzyskuję lepszy wynik (ale tylko w przypadku n=4), gdy używam odwróconej listy węzłów. To wyjaśnia magiczną część constructfunkcji.

Może być warto, poprawiając wybór. Ale ważniejsze wydaje się ponowne rozważenie usuniętych węzłów. W tej chwili nigdy więcej na nich nie patrzę. Niektóre z nich mogą być niepodłączone do żadnego z wybranych węzłów. Problem polega na tym, że nie wiem, które węzły tworzą niezależny zestaw. Po pierwsze, usunięcie węzłów przenumeruje pozostałe węzły. Można temu zaradzić, dołączając do nich atrybuty. Co gorsza, obliczenie liczby niepodległości po prostu podaje tę liczbę. Najlepszą alternatywą, jaką oferuje biblioteka, jest obliczenie wszystkich największych niezależnych zestawów, która jest wolniejsza (ile wydaje się zależeć od wielkości wykresu). Wydaje się jednak, że jest to najbliższa droga. O wiele bardziej niejasne wydaje mi się, że warto rozważyć, czy możemy użyć specjalnego sposobu definiowania wykresu.

Sprawa n=6może być osiągalna (wcale, niekoniecznie za 5 minut), jeśli zastąpię rekurencję pętlą, używając kolejki dla pozostałych składników.

Interesujące było dla mnie spojrzenie na składniki wykresów. Ponieważ n=4ich rozmiary to 168, 2*29, 2*28, 3, 4*2, 4*1. Tylko największego nie da się obsłużyć bezpośrednio.

Dla n=5, rozmiary są 1376, 2*128, 2*120, 119, several <=6.

Oczekuję, że te podwójne rozmiary będą odpowiadały grafom izomorficznym, ale używanie tego nie wydaje się opłacalne, ponieważ zawsze istnieje jeden dominujący największy składnik:

Ponieważ n=6największy komponent zawiera 11941węzły (łącznie 15425), kolejne dwa największe komponenty mają rozmiar 596.

Na n=7te numery są 107593 (125232), 2647.

Christian Sievers
źródło
Czy mógłbyś mi powiedzieć, co to jest zestaw dla 83, chcę wiedzieć, dlaczego mój algorytm nie osiąga tak wysokiego poziomu dla 4, ale jakoś wzrasta dla 5: P
fəˈnɛtɪk
To musi być g++ -std=c++11 -Wall -O3 -I/usr/include/igraph -o sievers sievers.cpp -ligraph. Ma znaczenie, gdzie -ligraphjest.
@ChristianSievers Jak działa generowanie krawędzi w kodzie?
fəˈnɛtɪk
@ChristianSievers Zastanawiałem się, w jaki sposób określa, z jakim każdym wierzchołkiem powinien się połączyć. Odwrócenie tablicy może to popsuć.
fəˈnɛtɪk
@ fəˈnɛtɪk Wektory odległości wydają się być posortowane według setI, aby uniknąć duplikatów, ale nawet nie pomyślałem o ich kolejności, kiedy napisałem ten kod. Wewnętrzna pętla, która zaczyna się od, po i+1prostu unika patrzenia na parę, a także na jej zamienioną wersję, która nie jest potrzebna, i jest najłatwiejszym sposobem uniknięcia pętli (krawędzi (a,a)). To nie zależy od kolejności, w jakiej przychodzą węzły, nie obchodzi mnie, czy dostanę (a,b)lub (b,a).
Christian Sievers,
3

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

Udało mi się zwiększyć wartość 4 za pomocą losowego usuwania elementów na początku mojego wyszukiwania. Co dziwne, usunięcie 20 elementów z więcej niż 6 połączeniami było szybsze niż usunięcie 5 elementów z więcej niż 8 połączeniami ...

Ta sekwencja prawdopodobnie nie jest optymalna dla 5 i może nie być optymalna dla 4. Żaden z węzłów nie jest jednak zbliżony do drugiego w zestawie.

Kod:

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));
}

Wypróbuj online!

Fragment, który można dodać na końcu programu, aby pokazać, jakie sekwencje odległości Hamminga wybrana sekwencja odległości Hamminga

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)
  }
}

Wyjaśnienie:

Po pierwsze, kod generuje wszystkie unikalne odległości uderzenia od podciągów.

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);
  }
}

Następnie kod konwertuje tę listę na niekierowany wykres

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
  }
}

Na koniec kod przechodzi przez ten wykres, usuwając wierzchołek z największą liczbą połączeń w każdym cyklu przed przywróceniem jakichkolwiek węzłów, które miałyby teraz mniej połączeń niż obecne maksimum. Po zakończeniu tego cyklu wyświetla liczbę pozostałych węzłów

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));

Zestawy:

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
Fəˈnɛtɪk
źródło
Dzięki za udzielenie pierwszej odpowiedzi! Czy mógłbyś podać przewodnik krok po kroku dla idiotów, jak uruchomić swój kod w Linuksie?
Może fəˈnɛtɪk mógłby zamienić swój kod w fragment kodu stosu?
mbomb007
@ mbomb007 z jakiegoś powodu, przekształcenie go we fragment kodu powoduje, że błąd 0 nie jest funkcją ... w linii dla (j = 0; j <t; j ++)
fəˈnɛtɪk
Może mógłbyś wypróbować JSFiddle?
mbomb007
Jeśli masz Chrome, możesz skopiować i wkleić kod do konsoli i uruchomić go, naciskając klawisz Enter. Nie do końca pewny co do innych przeglądarek. Chrome działa dla mnie szybciej niż systemy internetowe. Udało się uzyskać piątą wartość 349
f 17nɛtɪk