Zählen Sie, wie viele Abstandsfolgen von allen anderen weit entfernt sind

13

Der Hamming-Abstand zwischen zwei Saiten gleicher Länge ist die Anzahl der Positionen, an denen sich die entsprechenden Symbole unterscheiden.

Sei Peine binäre Zeichenkette der Länge nund Tsei eine binäre Zeichenkette der Länge 2n-1. Wir können die nHamming-Abstände zwischen Pund für jeden n-langen Teilstring Tin der Reihenfolge von links nach rechts berechnen und sie in ein Array (oder eine Liste) einfügen .

Beispiel Hamming-Distanz-Sequenz

Lass P = 101und T = 01100. Die Reihenfolge der Hamming-Abstände, die Sie von diesem Paar erhalten, ist 2,2,1.

Definition von Nähe

Betrachten wir nun zwei solcher Sequenzen von Hamming-Entfernungen. Sagen Sie x = (0, 2, 2, 3, 0)und y = (2, 1, 4, 4, 2)als Beispiele. Wir sagen das xund ysind closeob y <= x <= 2*yoder ob x <= y <= 2*x. Hier werden die Skalarmultiplikation und die Ungleichung elementweise genommen. Das heißt, für zwei Sequenzen Aund B, A <= B iff A[i] <= B[i]für alle Indizes i.

Man beachte , dass Sequenzen von Hamming - Abstände bilden eine Teilordnung im Rahmen dieser Weise , sie zu vergleichen. Mit anderen Worten, viele Paare von Sequenzen sind weder größer oder gleich noch kleiner oder gleich zueinander. Zum Beispiel (1,2)und (2,1).

Also anhand des obigen Beispiels, ist (0, 2, 2, 3, 0) <= 2*(2, 1, 4, 4, 2) = (4, 2, 8, 8, 4)aber (0, 2, 2, 3, 0)nicht größer als (2, 1, 4, 4, 2). Auch (2, 1, 4, 4, 2)ist nicht kleiner als oder gleich 2*(0, 2, 2, 3, 0) = (0, 4, 4, 6, 0). Infolgedessen xund ynicht nah beieinander.

Aufgabe

Berücksichtigen Sie zum Erhöhen nab n=1alle möglichen Paare von binären Zeichenfolgen Pder Länge nund Tder Länge 2n-1. Es gibt 2^(n+2n-1)solche Paare und damit viele Sequenzen von Hamming-Abständen. Viele dieser Sequenzen sind jedoch identisch. Die Aufgabe besteht darin, die Größe des größten Satzes von Hamming-Distanzsequenzen zu ermitteln, sodass keine zwei Sequenzen nahe beieinander liegen.

Ihr Code sollte eine Zahl pro Wert von ausgeben n.

Ergebnis

Ihre Punktzahl ist im Großen und Ganzen die höchste, die nIhr Code in 5 Minuten auf meinem Computer erreicht (aber lesen Sie weiter). Das Timing bezieht sich auf die Gesamtlaufzeit, nicht nur auf die Zeit dafür n.

Um nicht optimale Antworten bewerten zu können, benötigen wir ein etwas subtiles Bewertungssystem, da es wahrscheinlich schwierig ist, optimale Antworten zu finden. Ihre Punktzahl ist der höchste Wert, nfür den niemand eine höhere richtige Antwort für eine Größe veröffentlicht hat, die kleiner als diese ist. Wenn Sie beispielsweise ausgeben 2, 4, 21und jemand anderes ausgeben , 2, 5, 15erzielen Sie nur ein Ergebnis, 1wenn jemand anderes eine bessere Antwort auf diese Frage hat n = 2. Wenn Sie ausgeben 2, 5, 21, würden Sie 3unabhängig von den Ausgaben anderer Punkte erzielen , da diese Antworten alle optimal sind. Wenn Sie alle optimalen Antworten haben, erhalten Sie die Punktzahl für den höchsten nBeitrag, den Sie verfassen. Aber auch wenn Ihre Antwort nicht optimal ist, können Sie die Punktzahl erhalten, wenn niemand anders sie schlagen kann.

Beispielantworten und bearbeitetes Beispiel

(Diese Antwort ist noch nicht angekreuzt. Eine unabhängige Überprüfung wäre dankbar.)

Dank ETHproductions:

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

Schauen wir uns das n = 2genauer an. In diesem Fall lautet die vollständige Liste der Hamming-Distanzsequenzen (hier durch Tupel dargestellt):

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

Wir können sehen, dass dies (0,0)keinem anderen Tupel nahe kommt. In der Tat , wenn wir annehmen (0, 0), (0, 1), (1, 0), (2, 1), (1,2)dann keines dieser Tupel ist in der Nähe zu einem anderen. Dies ergibt eine Punktzahl von 5für n = 2.

Für n = 3die vollständige Liste der deutlichen Hamming - Distanz - Sequenzen ist:

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

Von diesen 48Sequenzen können wir eine Menge von Größen auswählen, 21so dass kein Paar in dieser Menge nahe beieinander liegt.

Sprachen und Bibliotheken

Sie können jede verfügbare Sprache und Bibliothek verwenden, die Sie mögen. Wo immer möglich, wäre es gut, wenn Sie Ihren Code ausführen könnten. Fügen Sie daher bitte eine vollständige Erklärung dazu bei, wie Sie Ihren Code unter Linux ausführen / kompilieren, wenn dies überhaupt möglich ist.

Mein Computer Die Timings werden auf meinem 64-Bit-Computer ausgeführt. Dies ist eine Ubuntu-Standardinstallation mit 8 GB RAM, AMD FX-8350 Eight-Core-Prozessor und Radeon HD 4250. Dies bedeutet auch, dass ich in der Lage sein muss, Ihren Code auszuführen.

Führende Antwort

  • Score von 4 für 2, 5, 21, 83, 361 von Christian Sievers. C ++
  • Score von 5 für 2, 5, 21, 83, 372 von fəˈnəˈtɛk. Javascript

quelle
Nachdem Sie sich Ihre Frage angeschaut haben, zeigt sie einige Ähnlichkeiten mit Spionen, die auf Hackerrank überarbeitet wurden. Dies ist ein NP-vollständiges Problem
am
@ fəˈnəˈtɛk Großartig! Beachten Sie, dass meine Frage keine optimalen Lösungen erfordert, um eine gute Punktzahl zu erhalten.
@ fəˈnəˈtɪk Kannst du auch die Antworten für 1,2,3 in der Frage bestätigen?
@ fəˈnəˈtɛk Ich bezweifle sehr, dass es NP-schwer ist. Sie müssten Set Packing oder ein anderes NP-vollständiges Problem in eine einzelne Ganzzahl mit nur einer polynomiellen Änderung der Problemgröße codieren.
297 eindeutige Hamming-Arrays für 4, 2040 eindeutige Arrays für 5
fɛnəˈtɛk

Antworten:

5

C ++ mit der igraph Bibliothek

Vielen Dank für eine schöne Gelegenheit, eine neue Bibliothek zu lernen!

Dieses Programm berechnet jetzt 2, 5, 21, 83, 361schnell. Sie können das Drucken der Knoten mit der PRINTNODESKonstante steuern .

Das verwendete Diagramm weist zusätzliche Kanten zwischen Knoten auf, die Distanzvektoren entsprechen, von denen einer in der Nähe (aber nicht gleich) des anderen in umgekehrter Richtung liegt. Das beschleunigt die Berechnung, und jede gefundene unabhängige Menge ist natürlich auch eine der Originalgraphen. Auch wenn es nicht vollständig erzwungen wird, wird die berechnete unabhängige Menge unter Umkehrung geschlossen. Ich glaube, es gibt immer eine maximale unabhängige Menge mit dieser Eigenschaft. Zumindest gibt es eine fürn<=4 . (Ich bin sicher, ich kann zeigen, dass 83 optimal ist.)

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

Um unter Debian zu kompilieren, installieren Sie libigraph0-devund tun g++ -std=c++11 -Wall -O3 -I/usr/include/igraph -o ig ig.cpp -ligraph.

Alte Beschreibung:

Die Igraph-Bibliothek hat eine Funktion zum Berechnen der maximalen Größe eines unabhängigen Scheitelpunktsatzes eines Graphen. Es kann mit diesem Problem umgehen n=3 in weniger als einer Sekunde und endet nicht in Tagen für n=4.

Ich zerlege also den Graphen in verbundene Komponenten und überlasse der Bibliothek den Umgang mit dem kleinen (kleiner als MAXDIRECT Knoten) Komponenten . Für die anderen Komponenten wähle ich einen Eckpunkt aus und lösche ihn. Im besten Fall wird das Diagramm dadurch in mehrere Komponenten aufgeteilt, in der Regel jedoch nicht. Wie auch immer, die Komponenten (vielleicht nur eine) sind kleiner und wir können die Rekursion verwenden.

Offensichtlich ist die Auswahl des Scheitelpunkts wichtig. Ich nehme nur einen von maximalem Grad. Ich habe festgestellt, dass ich ein besseres Ergebnis bekomme (aber nur fürn=4 ), wenn ich eine umgekehrte Knotenliste verwende. Das erklärt den magischen Teil der constructFunktion.

Es könnte sich lohnen, die Auswahl zu verbessern. Wichtiger erscheint es jedoch, die gelöschten Knoten zu überdenken. Im Moment schaue ich sie nie wieder an. Einige von ihnen sind möglicherweise nicht mit einem der ausgewählten Knoten verbunden. Das Problem ist, dass ich nicht weiß, welche Knoten die unabhängige Menge bilden. Zum einen werden beim Löschen von Knoten die verbleibenden Knoten neu nummeriert. Dies kann durch Anhängen von Attributen erledigt werden. Schlimmer noch, die Berechnung der Unabhängigkeitszahl ergibt nur diese Zahl. Die beste Alternative, die die Bibliothek bietet, besteht darin, alle größten unabhängigen Mengen zu berechnen , was langsamer ist (wie viel davon anscheinend von der Diagrammgröße abhängt). Dies scheint jedoch der unmittelbare Weg zu sein. Viel vager halte ich es auch für sinnvoll, zu prüfen, ob wir die spezielle Art und Weise verwenden können, in der das Diagramm definiert ist.

Der Fall wird n=6möglicherweise erreichbar (nicht unbedingt in 5 Minuten), wenn ich die Rekursion durch eine Schleife ersetze, die eine Warteschlange für die übrigen Komponenten verwendet.

Ich fand es interessant, die Komponenten der Grafiken zu betrachten. Denn n=4ihre Größen sind 168, 2*29, 2*28, 3, 4*2, 4*1. Nur der größte kann nicht direkt gehandhabt werden.

Denn n=5die Größen sind 1376, 2*128, 2*120, 119, several <=6.

Ich erwarte, dass diese doppelten Größen isomorphen Graphen entsprechen, aber es lohnt sich nicht, sie zu verwenden, da es immer eine einzige dominierende größte Komponente gibt:

Denn n=6die größte Komponente enthält 11941Knoten (von insgesamt 15425), die nächsten beiden größten Komponenten haben eine Größe 596.

Denn n=7diese Zahlen sind 107593 (125232), 2647.

Christian Sievers
quelle
Könnten Sie mich wissen lassen, wie hoch der Satz für 83 ist, ich möchte wissen, warum mein Algorithmus für 4 nicht so hoch wird, sondern für 5 irgendwie höher: P
fəˈnəˈtɛk
Es muss sein g++ -std=c++11 -Wall -O3 -I/usr/include/igraph -o sievers sievers.cpp -ligraph. Es ist wichtig, wo -ligraphist.
@ChristianSievers Wie funktioniert die Erzeugung von Kanten im Code?
20.
@ChristianSievers Ich habe mich gefragt, wie bestimmt wird, mit welchem ​​Scheitelpunkt eine Verbindung hergestellt werden soll. Das Umkehren des Arrays könnte das vermasseln.
20.
@ fəˈnəˈtɪk Die Abstandsvektoren scheinen aus der Reihenfolge heraus zu kommen, die setich verwende, um Duplikate zu vermeiden, aber ich habe nicht einmal an ihre Reihenfolge gedacht, als ich diesen Code geschrieben habe. Die innere Schleife, die bei beginnt, i+1vermeidet das Betrachten eines Paares und auch die vertauschte Version, die nicht benötigt wird, und ist der einfachste Weg, um Schleifen (Kanten (a,a)) zu vermeiden . Es hängt nicht von der Reihenfolge ab, in der die Knoten kommen. Es ist mir egal, ob ich (a,b)oder bekomme (b,a).
Christian Sievers
3

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

Es ist mir gelungen, den Wert für 4 durch zufälliges Entfernen von Elementen zu Beginn meiner Suche zu erhöhen. Seltsamerweise war das Entfernen von 20 Elementen mit mehr als 6 Verbindungen schneller als das Entfernen von 5 Elementen mit mehr als 8 Verbindungen ...

Diese Sequenz ist wahrscheinlich nicht optimal für 5 und möglicherweise nicht optimal für 4. Keiner der Knoten befindet sich jedoch in der Menge in der Nähe eines anderen.

Code:

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

Probieren Sie es online!

Ausschnitt, der am Ende des Programms hinzugefügt werden kann, um anzuzeigen, welche Hamming-Distanzsequenzen für jede ausgewählte Hamming-Distanzsequenz gelten

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

Erläuterung:

Zunächst generiert der Code alle eindeutigen Hamming-Abstände von den Teilzeichenfolgen.

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

Als nächstes konvertiert der Code diese Liste in ein ungerichtetes Diagramm

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

Schließlich durchläuft der Code dieses Diagramm und entfernt den Scheitelpunkt mit den meisten Verbindungen in jedem Zyklus, bevor Knoten wiederhergestellt werden, die jetzt weniger Verbindungen als das aktuelle Maximum haben würden. Wenn dieser Zyklus beendet ist, wird die Anzahl der verbleibenden Knoten ausgegeben

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

Sätze:

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
quelle
Vielen Dank für die erste Antwort! Könnten Sie bitte Idioten eine Schritt-für-Schritt-Anleitung geben, wie Sie Ihren Code unter Linux ausführen können?
Vielleicht könnte Fəˈnəˈtɪk seinen Code in ein Stapel-Snippet verwandeln?
mbomb007
@ mbomb007 Aus irgendeinem Grund wird der Fehler 0 nicht als Funktion in der Zeile für (j = 0; j <t; j ++)
fəˈnəˈtɛk
Vielleicht könntest du JSFiddle ausprobieren?
mbomb007
Wenn Sie über Chrome verfügen, können Sie den Code kopieren, in die Konsole einfügen und mit der Eingabetaste ausführen. Nicht ganz sicher über andere Browser. Chrome führt den Code für mich schneller aus als die Online-Systeme. Es ist
gelungen