Comptez combien de séquences de distance sont loin de toutes les autres

13

La distance de Hamming entre deux chaînes de longueur égale est le nombre de positions auxquelles les symboles correspondants sont différents.

Soit Pune chaîne binaire de longueur net Tune chaîne binaire de longueur 2n-1. Nous pouvons calculer les ndistances de Hamming entre Pet chaque nsous-chaîne de longueur Tdans l'ordre de gauche à droite et les mettre dans un tableau (ou une liste).

Exemple de séquence de distance de Hamming

Soit P = 101et T = 01100. La séquence des distances de Hamming que vous obtenez de cette paire est 2,2,1.

Définition de proximité

Considérons maintenant deux de ces séquences de distances de Hamming. Dites x = (0, 2, 2, 3, 0)et y = (2, 1, 4, 4, 2)comme exemples. Nous disons cela xet ysommes closesi y <= x <= 2*you si x <= y <= 2*x. Ici, la multiplication scalaire et l'inégalité sont prises élément par élément. C'est - à - dire pour deux séquences Aet B, A <= B iff A[i] <= B[i]pour tous les indices i.

Notez que les séquences de distances de Hamming forment un ordre partiel sous cette façon de les comparer. En d'autres termes, de nombreuses paires de séquences ne sont ni supérieures ni égales ni inférieures ou égales les unes aux autres. Par exemple (1,2)et (2,1).

Donc, en utilisant l'exemple ci-dessus, (0, 2, 2, 3, 0) <= 2*(2, 1, 4, 4, 2) = (4, 2, 8, 8, 4)mais (0, 2, 2, 3, 0)n'est pas plus grand que (2, 1, 4, 4, 2). N'est (2, 1, 4, 4, 2)pas non plus inférieur ou égal à 2*(0, 2, 2, 3, 0) = (0, 4, 4, 6, 0). En conséquence xet yne sont pas proches les uns des autres.

Tâche

Pour augmenter à npartir de n=1, considérez toutes les paires possibles de chaînes binaires Pde longueur net Tde longueur 2n-1. Il existe de 2^(n+2n-1)telles paires et donc de nombreuses séquences de distances de Hamming. Cependant, bon nombre de ces séquences seront identiques. La tâche consiste à trouver la taille du plus grand ensemble de séquences de distance de Hamming afin qu'il n'y ait pas deux séquences proches l'une de l'autre.

Votre code doit afficher un nombre par valeur de n.

But

Votre score est globalement le plus élevé natteint par votre code sur ma machine en 5 minutes (mais lisez la suite). Le timing est pour le temps de fonctionnement total, pas le temps juste pour cela n.

Afin de donner des scores pour les réponses non optimales, parce que trouver des réponses optimales est probablement difficile, nous aurons besoin d'un système de notation légèrement subtil. Votre score est la valeur la plus élevée npour laquelle personne d'autre n'a publié de réponse correcte plus élevée pour toute taille inférieure ou égale à celle-ci. Par exemple, si vous sortez 2, 4, 21et que quelqu'un d'autre sort, 2, 5, 15vous ne marquerez 1que si quelqu'un d'autre a une meilleure réponse pour n = 2. Si vous produisez, 2, 5, 21vous obtiendrez un score, 3peu importe ce que quelqu'un d'autre produit car ces réponses sont toutes optimales. De toute évidence, si vous avez toutes les réponses optimales, vous obtiendrez le score le plus élevé que nvous publiez. Cependant, même si votre réponse n'est pas optimale, vous pouvez toujours obtenir le score si personne d'autre ne peut le battre.

Exemples de réponses et d'exemples fonctionnels

(Ces réponses ne sont pas encore vérifiées. Une vérification indépendante serait grandement appréciée.)

Merci à ETHproductions:

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

Regardons n = 2plus en détail. Dans ce cas, la liste complète des séquences de distance de Hamming (représentées ici par des tuples) est:

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

Nous pouvons voir que ce (0,0)n'est pas proche de tout autre tuple. En fait , si nous prenons (0, 0), (0, 1), (1, 0), (2, 1), (1,2)alors aucun de ces tuples sont proches de l' un des autres. Cela donne un score de 5pour n = 2.

Pour n = 3la liste complète des séquences distinctes de distance de Hamming:

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

De ces 48séquences, nous pouvons choisir un ensemble de taille 21afin qu'aucune paire de cet ensemble ne soit proche l'une de l'autre.

Langues et bibliothèques

Vous pouvez utiliser toutes les langues et bibliothèques disponibles que vous aimez. Dans la mesure du possible, il serait bon de pouvoir exécuter votre code, veuillez donc inclure une explication complète sur la façon d'exécuter / compiler votre code sous Linux si possible.

Ma machine Les temporisations seront exécutées sur ma machine 64 bits. Il s'agit d'une installation Ubuntu standard avec 8 Go de RAM, processeur AMD FX-8350 à huit cœurs et Radeon HD 4250. Cela signifie également que je dois pouvoir exécuter votre code.

Réponse principale

  • Score de 4 pour 2, 5, 21, 83, 361 par Christian Sievers. C ++
  • Score de 5 pour 2, 5, 21, 83, 372 par fəˈnɛtɪk. Javascript

la source
Après avoir examiné votre question, elle montre des similitudes avec les espions, révisés sur hackerrank, qui est un problème NP-complet
fəˈnɛtɪk
@ fəˈnɛtɪk Super! Notez que ma question ne nécessite pas de solutions optimales pour obtenir un bon score.
@ fəˈnɛtɪk Pouvez-vous également confirmer les réponses pour 1,2,3 dans la question?
@ fəˈnɛtɪk Je doute fort que ce soit NP-difficile. Vous devrez encoder Set Packing ou un autre problème NP-complete en un seul entier avec seulement un changement polynomial de la taille du problème.
297 matrices uniques de hamming pour 4, 2040 matrices uniques pour 5
fəˈnɛtɪk

Réponses:

5

C ++ utilisant la bibliothèque igraph

Merci pour cette belle opportunité d'apprendre une nouvelle bibliothèque!

Ce programme calcule désormais 2, 5, 21, 83, 361rapidement. Vous pouvez contrôler l'impression des nœuds avec la PRINTNODESconstante.

Le graphe utilisé a des arêtes supplémentaires entre les nœuds correspondant à des vecteurs de distance où l'un est proche (mais pas égal) de l'autre inversé. Cela accélère le calcul, et tout ensemble indépendant trouvé est bien sûr également l'un des graphiques d'origine. De plus, même s'il n'est pas complètement appliqué, l'ensemble indépendant calculé est fermé sous réversion. Je crois qu'il existe toujours un ensemble indépendant maximal avec cette propriété. Il y en a au moins un pour n<=4. (Je suis sûr que je peux montrer que 83 est optimal.)

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

Pour compiler sur Debian, installez libigraph0-devet faites g++ -std=c++11 -Wall -O3 -I/usr/include/igraph -o ig ig.cpp -ligraph.

Ancienne description:

La bibliothèque igraph a une fonction pour calculer la taille maximale d'un ensemble de sommets indépendant d'un graphe. Il peut gérer ce problème jusqu'à n=3en moins d'une seconde et ne se termine pas en quelques jours n=4.

Donc, ce que je fais, c'est décomposer le graphique en composants connectés et laisser la bibliothèque gérer les petits MAXDIRECTcomposants (moins que les nœuds). Pour les autres composants, je sélectionne un sommet et le supprime. Dans le meilleur des cas, cela divise le graphique en plusieurs composants, mais ce n'est généralement pas le cas. Quoi qu'il en soit, les composants (peut-être un seul) sont plus petits et nous pouvons utiliser la récursivité.

Évidemment, la sélection du sommet est importante. Je prends juste un de degré maximal. J'ai trouvé que j'obtiens de meilleurs résultats (mais seulement pour n=4) lorsque j'utilise une liste de nœuds inversée. Cela explique la partie magique de la constructfonction.

Cela pourrait valoir la peine d'améliorer la sélection. Mais il semble plus important de reconsidérer les nœuds supprimés. En ce moment, je ne les regarde plus jamais. Certains d'entre eux peuvent être déconnectés de l'un des nœuds sélectionnés. Le problème est que je ne sais pas quels nœuds forment l'ensemble indépendant. D'une part, la suppression de nœuds renumérote les nœuds restants. Cela peut être géré en leur attachant des attributs. Mais pire, le calcul du nombre d'indépendance donne juste ce nombre. La meilleure alternative proposée par la bibliothèque est de calculer tous les plus grands ensembles indépendants, ce qui est plus lent (combien semble dépendre de la taille du graphique). Pourtant, cela semble la voie à suivre immédiate. Beaucoup plus vaguement, je pense également qu'il pourrait être utile de considérer si nous pouvons utiliser la façon particulière dont le graphique est défini.

Le cas n=6pourrait devenir accessible (du tout, pas nécessairement en 5 minutes) si je remplace la récursivité par une boucle utilisant une file d'attente pour les composants restants.

J'ai trouvé intéressant de regarder les composants des graphiques. Car n=4, leurs tailles sont 168, 2*29, 2*28, 3, 4*2, 4*1. Seul le plus gros ne peut pas être traité directement.

Pour n=5, les tailles sont 1376, 2*128, 2*120, 119, several <=6.

Je m'attends à ce que ces tailles doubles correspondent à des graphiques isomorphes, mais cela ne semble pas valoir la peine car il y a toujours un seul composant dominant dominant:

Pour n=6, le plus grand composant contient des 11941nœuds (sur un total de 15425), les deux plus grands composants suivants ont une taille 596.

Car n=7, ces chiffres le sont 107593 (125232), 2647.

Christian Sievers
la source
Pourriez-vous me faire savoir quel est l'ensemble pour 83, je veux savoir pourquoi mon algorithme n'atteint pas ce niveau élevé pour 4, mais devient en quelque sorte plus élevé pour 5: P
fəˈnɛtɪk
Ça doit être g++ -std=c++11 -Wall -O3 -I/usr/include/igraph -o sievers sievers.cpp -ligraph. Il importe où -ligraphest.
@ChristianSievers Comment fonctionne la génération d'arêtes dans le code?
fəˈnɛtɪk
@ChristianSievers Je me demandais comment cela détermine à quoi chaque sommet doit se connecter. Inverser la baie peut être un problème.
fəˈnɛtɪk
@ fəˈnɛtɪk Les vecteurs de distance semblent être triés de ceux setque j'utilise pour éviter les doublons, mais je n'ai même pas pensé à leur ordre quand j'ai écrit ce code. La boucle intérieure commençant à i+1évite simplement de regarder une paire et aussi sa version permutée qui n'est pas nécessaire, et est le moyen le plus simple d'éviter les boucles (bords (a,a)). Cela ne dépend pas de l'ordre dans lequel les nœuds viennent, je m'en fiche si j'obtiens (a,b)ou (b,a).
Christian Sievers
3

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

Géré pour augmenter la valeur de 4 en utilisant la suppression aléatoire des éléments au début de ma recherche. Curieusement, la suppression de 20 éléments avec plus de 6 connexions était plus rapide que la suppression de 5 éléments avec plus de 8 connexions ...

Cette séquence n'est probablement pas optimale pour 5 et pourrait ne pas être optimale pour 4. Cependant, aucun des nœuds n'est proche d'un autre dans l'ensemble.

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

Essayez-le en ligne!

Extrait qui peut être ajouté à la fin du programme pour montrer quelles séquences de distance de Hamming chaque séquence de distance de Hamming sélectionnée

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

Explication:

Tout d'abord, le code génère toutes les distances de hamming uniques à partir des sous-chaînes.

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

Ensuite, le code convertit cette liste en un graphique non orienté

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

Enfin, le code parcourt ce graphique, supprimant le sommet avec le plus de connexions à chaque cycle avant de restaurer les nœuds qui auraient désormais moins de connexions que le maximum actuel. Une fois ce cycle terminé, il affiche le nombre de nœuds restants

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

Ensembles:

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
la source
Merci d'avoir donné la première réponse! Pourriez-vous donner un guide étape par étape pour les idiots sur la façon d'exécuter votre code sous Linux s'il vous plaît?
Peut-être que fəˈnɛtɪk pourrait transformer son code en un extrait de pile?
mbomb007
@ mbomb007 pour une raison quelconque, en faire un extrait de code, l'erreur 0 n'est pas une fonction ... dans la ligne pour (j = 0; j <t; j ++)
fəˈnɛtɪk
Vous pourriez peut-être essayer JSFiddle?
mbomb007
Si vous avez Chrome, vous pouvez copier coller le code dans la console et l'exécuter en appuyant sur Entrée. Pas tout à fait sûr des autres navigateurs. Pour moi, Chrome exécute le code plus rapidement que les systèmes en ligne. Réussi à obtenir une 5e valeur de 349
fəˈnɛtɪk