Fai la NP: trova la cricca più grande


22

sfondo

Al momento della stesura di questo, il problema P vs NP è ancora irrisolto, ma potresti aver sentito parlare del nuovo documento di Norbert Blum che afferma la prova che P! = NP, che è già sospettato di essere errato (ma vedremo).

Il problema discusso in questo documento è il problema della cricca . Almeno questo è quello che ho letto in un articolo di giornale, quindi correggimi se sbaglio, ma in ogni caso, vorrei che tu scrivessi un programma che risolva la seguente variante:

L'obiettivo

Supponiamo di avere una grande scuola con molti studenti. Ognuno di questi studenti ha alcuni amici in questa scuola. Una cricca di studenti è un gruppo composto solo da studenti amici degli altri membri .

Il tuo programma riceverà coppie di studenti amici come input. Da queste informazioni, il programma deve trovare la dimensione della cricca più grande . Gli studenti sono identificati da ID interi .

Se preferisci termini matematici, questo significa che sei alimentato dai bordi di un grafico non orientato, identificato da due nodi ciascuno.

Ingresso

Il tuo input sarà un elenco non vuoto di coppie di numeri interi positivi, ad es [[1,2],[2,5],[1,5]]. Puoi prendere questo input in qualsiasi forma ragionevole, ad esempio come una matrice di matrici, come righe di testo contenenti due numeri ciascuna, ecc ...

Produzione

L'output previsto è un singolo numero n >= 2: la dimensione della cricca più grande. Con l'ingresso esempio di cui sopra, il risultato sarebbe stato 3, come tutti gli studenti ( 1, 2e 5) sono amici tra di loro.

Casi test

[[1,2]]
=> 2

[[1,2],[3,1],[3,4]]
=> 2

[[1,2],[2,5],[1,5]]
=> 3

[[2,5],[2,3],[4,17],[1,3],[7,13],[5,3],[4,3],[4,1],[1,5],[5,4]]
=> 4 (the largest clique is [1,3,4,5])

[[15,1073],[23,764],[23,1073],[12,47],[47,15],[1073,764]]
=> 3 (the largest clique is [23,764,1073])

[[1296,316],[1650,316],[1296,1650],[1296,52],[1650,711],[711,316],[1650,52],
 [52,711],[1296,711],[52,316],[52,1565],[1565,1296],[1565,316],[1650,1565],
 [1296,138],[1565,138],[1565,711],[138,1650],[711,138],[138,144],[144,1860],
 [1296,1860],[1860,52],[711,1639]]
=> 6 (the largest clique is [52,316,711,1296,1565,1650])

È possibile utilizzare questa (stupida) implementazione di riferimento (stampa un output extra con -dflag) per verificare i risultati di altri casi di test.

Le regole

  1. Il tuo programma non ha bisogno di un risultato definito su input non validi. Quindi puoi presumere che:
    • otterrai sempre almeno una coppia di ID
    • ogni coppia è composta da due ID diversi
    • nessuna coppia appare due volte (scambiando i posti degli ID sarebbe sempre la stessa coppia)
  2. Al tuo algoritmo non è consentito impostare un limite superiore sulla dimensione di input. Le limitazioni puramente tecniche e le limitazioni stabilite dalla tua lingua / ambiente (come dimensioni dello stack, tempo di calcolo, ecc.) Sono ovviamente inevitabili.
  3. Sono vietate le scappatoie standard.
  4. Questo è , quindi vince il codice più breve, misurato in byte.
  5. Se l'algoritmo presenta una complessità temporale polinomiale, ottieni un punteggio -1immediatamente indipendentemente dalla dimensione del codice, ma in tal caso, potresti voler inviare la tua soluzione da qualche altra parte. ;)

4
Posso quasi garantire che ci sarà qualcuno che lo farà (o proverà a farlo), quindi sarebbe semplicemente più sicuro rimuoverlo. Se vuoi premiare le persone per averlo fatto, puoi offrire una generosità alla risposta più breve che lo fa nel tempo polinomiale.
caird coinheringaahing il

4
@cairdcoinheringaahing se qualcuno lo fa, -1è ben meritato ;)
Felix Palmen,

13
@cairdcoinheringaahing Se qualcuno è riuscito a dimostrare che P = NP, avere il punteggio più basso automatico su un problema di codice golf è il minimo dei nostri dubbi. Detto questo, la Regola 5 non contribuisce molto alla sfida, quindi sono d'accordo che dovrebbe essere rimosso.
Mego

11
@Mego contribuisce semplicemente uno scherzo e un piccolo bonus al 1M offerto da CMI.
Felix Palmen,

30
Bene, non lo farò, a favore delle poche persone che hanno un certo senso di "umorismo scientifico". Per favore, non commentare altri suggerimenti a riguardo, grazie :)
Felix Palmen,

Risposte:


6

Gelatina ,  15 18  16 byte

+3 byte per correggere i bug nel mio metodo.
-2 byte grazie alle miglia (rilevando che n × (n-1) ÷ 2 = nC2 )

ẎQL©c2⁼Lȧ®
ŒPÇ€Ṁ

Un collegamento monadico che prende l'elenco delle amicizie (bordi) e restituisce un numero intero.

Provalo online! forma il power-set dei bordi in memoria, quindi è inefficiente sia nello spazio che nel tempo (sì, ecco O (2 n ) gente)!

Come?

ẎQL©c2⁼Lȧ® - Link 1, isClique?: list, edges  e.g. [[1,3],[2,3],[3,4],[4,1],[4,2],[2,1]]
Ẏ          - tighten                              [ 1,3 , 2,3 , 3,4 , 4,1 , 4,2 , 2,1 ]
 Q         - de-duplicate (gets unique ids)          [1,3,2,4]
  L        - length (get number of people involved)  4
   ©       - (copy to the register)
    c2     - combinations of 2 (z-choose-2)          6
       L   - length (of edges)                       6
      ⁼    - equal?                                  1
         ® - recall value from register              4
        ȧ  - logical and                             4
           - (Note: the number of edges of a clique of size n is n*(n-1) and we're
           -  guaranteed no repeated edges and that all edges are two distinct ids)

ŒPÇ€Ṁ - Link: list of lists, edges
ŒP    - power-set (all possible sets of edges (as lists))
  Ç€  - call last link (1) as a monad for €ach
    Ṁ - maximum

Wow, spiegazione quando hai tempo per favore
Mr. Xcoder

@EriktheOutgolfer Sono d'accordo. Probabilmente posso aggiungere il codice per il salvataggio ...
Jonathan Allan,



@miles - bello, ho appena trascorso un po 'di tempo cercando di ottenere un 15 da quello, penso che dovrebbe essere possibile!
Jonathan Allan,

13

Mathematica, 34 byte

Tr[1^#&@@FindClique[#<->#2&@@@#]]&  

Fondamentalmente FindClique fa il lavoro e "trova una cricca più grande nel grafico g."
Tutto il resto sta convertendo la lista di input in grafico

Ingresso

[{{2, 5}, {2, 3}, {4, 17}, {1, 3}, {7, 13}, {5, 3}, {4, 3}, {4, 1}, {1, 5}, {5, 4}}]

Produzione

4

Ingresso

[{{1296, 316}, {1650, 316}, {1296, 1650}, {1296, 52}, {1650, 711}, {711, 316}, {1650, 52}, {52, 711}, {1296, 711}, {52, 316}, {52, 1565}, {1565, 1296}, {1565, 316}, {1650, 1565}, {1296, 138}, {1565, 138}, {1565 , 711}, {138, 1650}, {711, 138}, {138, 144}, {144, 1860}, {1296, 1860}, {1860, 52}, {711, 1639}}]

Produzione

6

grazie @Kelly Lowder per -10 byte


23
Ovviamente Mathematica ha una struttura per questo.
Erik the Outgolfer,

1
Elimina 10 byte conTr[1^#&@@FindClique[#<->#2&@@@#]]&
Kelly Lowder il

12
FindCliqueಠ ___ ಠ
Mr. Xcoder

6

Gelatina , 20 byte

ŒPẎ€µQL’=ċЀ`ẠµÐfṪQL

Provalo online!

Naturalmente questo non merita il milione: p

Questo avrebbe battuto Pyth, se non per il µ(...)µe 2 byte Ðf.


Stupefacente. Potrei anche rinunciare ora.
Mark Thomas,

@FelixPalmen brute force: p
Erik the Outgolfer

@EriktheOutgolfer Non intendevo il tempo di esecuzione del codice;)
Felix Palmen,

@FelixPalmen Voglio dire, l'approccio della forza bruta non ha bisogno di molte riflessioni: p
Erik the Outgolfer

Fornisce un MemoryError con il più grande test-case :( Naturalmente ancora valido, si tratta di una "limitazione tecnica" - ma solo per curiosità, c'è un modo per aumentare le risorse disponibili con la gelatina?
Felix Palmen,

3

J , 36 byte

[:>./](#(]*[=2!])#@~.@,)@#~2#:@i.@^#

Provalo online!

Corre nel tempo O (2 n ) dove n è il numero di coppie.

Una soluzione più veloce per 65 byte è

3 :'$>{._2{~.@((+.&(e.&y)&<|.)@(-.,-.~)&>/#&,/:~@~.@,&.>/)~^:a:y'

Provalo online!

Spiegazione

[:>./](#(]*[=2!])#@~.@,)@#~2#:@i.@^#  Input: list of pairs
                                   #  Length
                           2      ^   2^n
                               i.@    Range [0, 2^n)
                            #:@       Binary
                         #~           Copy
      (                )@             For each
                      ,                 Flatten
                   ~.@                  Unique
                 #@                     Length
        (       )                       Dyad with RHS at previous and LHS as next
               ]                          Get RHS
             2!                           Binomial coefficient, choose 2
            =                             Equals
           [                              Get LHS
          *                               Times
         ]                                Get RHS
       #                                Length
[:>./                                 Reduce using maximum


2

Python 2 , 180 byte

G=input()
m=0
L=len
for i in range(2**L(G)):
 u=[];p=sum([G[j]for j in range(L(G))if 2**j&i],u)
 for j in p:u+=[j][j in u:]
 m=max(m,L(u)*all(p.count(j)==L(u)-1for j in u))
print m

Provalo online!

-2 grazie a shooqie .
-1 grazie a Mr. Xcoder .
-3 grazie a ricorsivo .


È possibile salvare due byte assegnando lena una variabile
shooqie il

183 byte . (x not in y)significa 0**(x in y).
Mr. Xcoder,

@ Mr.Xcoder sapevo che c'era un modo per accorciarlo! Grazie!
Erik the Outgolfer,

Non l'ho mai usato prima, solo un trucco che mi è passato per la testa un paio di giorni fa ma non ci sono ancora riuscito.
Mr. Xcoder,

@ Mr.Xcoder Non importa, se funziona, allora perché no? : D BTW è anche possibile sostituire 0**con -~-.
Erik the Outgolfer,

1

Pyth, 28 byte

l{sSef<T.{SMQm.{ft{T.Cd2yS{s

Provalo online

Spiegazione

l{sSef<T.{SMQm.{ft{T.Cd2yS{s
                         S{sQ  Get the distinct nodes in the (implicit) input.
                        y      Take every subset.
             m      .Cd2       Get the pairs...
                ft{T           ... without the [x, x] pairs...
              .{               ... as sets.
     f<T                        Choose the ones...
        .{  Q                   ... which are subsets of the input...
          SM                    ... with edges in sorted order.
    e                           Take the last element (largest clique).
l{sS                            Get the number of distinct nodes.

1

Python 3 , 162 159 byte

lambda x,f=lambda x:{i for s in x for i in s}:len(f(x))if all([(y,z)in x or(z,y)in x for y in f(x)for z in f(x)if y<z])else max(c(x.difference({y}))for y in x)

Provalo online!

La funzione c prende i vertici sotto forma di un insieme di tuple ordinate ({(x, y), ...} dove x è minore di y). Una funzione chiamata "entry" si trova nell'intestazione TIO per testare con i dati in un elenco di formati di elenchi non ordinati . Se cricca, restituisce la lunghezza. Se non è cricca, restituisce la dimensione massima della cricca dei vertici, meno un vertice per ciascun vertice nei vertici. Supera il tempo dell'ultimo caso di test in TIO

Aggiornamento: "o (z, y) in x" porzione aggiunta per rimuovere la dipendenza da ordinamento "f = lambda x: {i per s in x per i in s}" invece di itertools.chain racchiuso in set.

-minus 3 byte grazie a @Jonathan Allen



A parte - non hai bisogno di nominare c, quindi puoi rimuoverlo c=(dovresti mettere c=\alla fine dell'intestazione e posizionare la lambdaparte superiore del blocco di codice per TIO)
Jonathan Allan

Inoltre è possibile sbarazzarsi dis e sostituire s(...)con {*...}consentire la rimozione anche di alcuni spazi.
Jonathan Allan,

1
@JonathanAllan grazie, risolto il problema
Conner Johnston


1

Gelatina , 28 byte

œ^e³;U¤
Œcç/Ðfœ|Ṣ¥/€QµÐĿ-ịḢL

Provalo online!

Soluzione più rapida in grado di risolvere l'ultimo caso di test in un secondo su TIO.


E che complessità ha? Se è inferiore a O (2ⁿ) , merita $ 1.000.000.
Erik the Outgolfer

1
@EriktheOutgolfer, ti sbagli, ci sono algoritmi con runtime O (1.1888ⁿ) .
rus9384,

In aggiunta a ciò, per valere un milione, npotrebbe apparire solo nelle basi :)
Felix Palmen,

@FelixPalmen, oppure no. Ad ogni modo, per milioni di una delle due dichiarazioni deve essere dimostrata.
rus9384,

1
Credo che questo sia O (1.414 ^ n). Puoi vedere prestazioni peggiori quando l'input è un grafico completo.
miglia

1

Java + Guava 23.0, 35 + 294 = 329 byte

import com.google.common.collect.*;
a->{int l=0,o=1,c,z=a.size();for(;o>0&l<z;){o=0;c:for(Iterable<int[]>s:Sets.combinations(a,l*(l+1)/2)){Multiset<Integer>m=TreeMultiset.create();for(int[]x:s){m.add(x[0]);m.add(x[1]);}c=m.elementSet().size();for(int e:m.elementSet())if (m.count(e)!=c-1)continue c;l+=o=1;break;}}return z<3?2:l;}

Questo algoritmo non rappresenta graficamente, ma genera invece tutte le combinazioni di coppie, di dimensioni specifiche. Inserisco tutte le combinazioni di coppie in un multiset e controllo che abbiano tutte le dimensioni previste (il numero di voci univoche - 1). Se lo fanno, ho trovato una cricca e vado a cercarne una più grande.

Dalla libreria Guava, utilizzo il nuovo combinationsmetodo e il tipo di raccolta strumenti Multiset.

Ungolfed

import com.google.common.collect.*;
import java.util.function.*;

public class Main {

  public static void main(String[] args) {
    ToIntFunction<java.util.Set<int[]>> f
        = a -> {
          int l = 0, o = 1, c, z = a.size();
          for (; o > 0 & l < z;) {
            o = 0;
            c:
            for (Iterable<int[]> s : Sets.combinations(a, l * (l + 1) / 2)) {
              Multiset<Integer> m = TreeMultiset.create();
              for (int[] x : s) {
                m.add(x[0]);
                m.add(x[1]);
              }
              c = m.elementSet().size();
              for (int e : m.elementSet()) {
                if (m.count(e) != c - 1) {
                  continue c;
                }
              }
              l += o = 1;
              break;
            }
          }
          return z < 3 ? 2 : l;
        };
    int[][][] tests = {
      {{1, 2}},
      {{1, 2}, {3, 1}, {3, 4}},
      {{1, 2}, {2, 5}, {1, 5}},
      {{2, 5}, {2, 3}, {4, 17}, {1, 3}, {7, 13}, {5, 3}, {4, 3}, {4, 1}, {1, 5}, {5, 4}},
      {{15, 1073}, {23, 764}, {23, 1073}, {12, 47}, {47, 15}, {1073, 764}},
      {{1296, 316}, {1650, 316}, {1296, 1650}, {1296, 52}, {1650, 711}, {711, 316}, {1650, 52}, {52, 711}, {1296, 711}, {52, 316}, {52, 1565}, {1565, 1296}, {1565, 316}, {1650, 1565}, {1296, 138}, {1565, 138}, {1565, 711}, {138, 1650}, {711, 138}, {138, 144}, {144, 1860}, {1296, 1860}, {1860, 52}, {711, 1639}}
    };
    for (int[][] test : tests) {
      java.util.Set<int[]> s = new java.util.HashSet<int[]>();
      for (int[] t : test) {
        s.add(t);
      }
      System.out.println(f.applyAsInt(s));
    }
  }
}

Sarei molto sorpreso, vedi Trovare il massimo di cricche in grafici arbitrari - ma mi ci vorrà un po 'per analizzare questo codice, non ho troppa familiarità con Java :)
Felix Palmen

@FelixPalmen Mi è piaciuta questa sfida, quindi la mia risposta rimarrà in ogni caso, ma sto bene con la rimozione di "-1" se non è una complessità polinomiale. Quindi probabilmente dovrei andare a recensire alcuni libri: P
Olivier Grégoire,

"La combinazione di dimensioni xè polinomiale " <- sei sicuro? Immagino sia questo il metodo usato . Il valore restituito è un AbstractSetcon un iteratore e il forciclo seguente chiamerà questo iteratore x!volte se non sbaglio ...
Felix Palmen

Correzione: purché x < n(con nla dimensione completa del set di input), non è n!/(x!(n-x)!)ancora polinomiale :)
Felix Palmen

@FelixPalmen Probabilmente hai ragione. Inoltre, stai dicendo che se faccio un combinationsmetodo che è X^n(che è del tutto possibile), posso ottenerlo? Nel frattempo, rimuovo la mia richiesta di "-1".
Olivier Grégoire,


0

6502 codice macchina (C64), 774 703 byte

(Io solo dovuto fare questo, il mio C64 può fare tutto ... hehe)

hexdump:

00 C0 A9 00 A2 08 9D 08 00 CA 10 FA A2 04 9D FB 00 CA 10 FA 20 54 C0 B0 20 AD 
C9 C2 AE CA C2 20 92 C1 B0 31 8D 31 C0 AD CB C2 AE CC C2 20 92 C1 B0 23 A2 FF 
20 FE C1 90 DB 20 6A C2 20 C1 C1 B0 05 20 6A C2 50 F6 A5 FB 8D D3 C2 20 43 C1 
A9 CD A0 C2 20 1E AB 60 A2 00 86 CC 8E 61 C0 20 E4 FF F0 FB A2 FF C9 0D F0 10 
E0 0B 10 0C 9D BD C2 20 D2 FF E8 8E 61 C0 D0 E5 C6 CC A9 20 20 D2 FF A9 0D 20 
D2 FF A9 00 9D BD C2 AA BD BD C2 F0 5C C9 30 30 0E C9 3A 10 0A 9D CD C2 E8 E0 
06 F0 4C D0 E9 C9 20 D0 46 A9 00 9D CD C2 E8 8E BC C0 20 EB C0 AD D3 C2 8D C9 
C2 AD D4 C2 8D CA C2 A2 FF A0 00 BD BD C2 F0 0F C9 30 30 21 C9 3A 10 1D 99 CD 
C2 C8 E8 D0 EC A9 00 99 CD C2 20 EB C0 AD D3 C2 8D CB C2 AD D4 C2 8D CC C2 18 
60 38 60 A2 FF E8 BD CD C2 D0 FA A0 06 88 CA 30 0A BD CD C2 29 0F 99 CD C2 10 
F2 A9 00 99 CD C2 88 10 F8 A9 00 8D D3 C2 8D D4 C2 A2 10 A0 7B 18 B9 53 C2 90 
02 09 10 4A 99 53 C2 C8 10 F2 6E D4 C2 6E D3 C2 CA D0 01 60 A0 04 B9 CE C2 C9 
08 30 05 E9 03 99 CE C2 88 10 F1 30 D2 A2 06 A9 00 9D CC C2 CA D0 FA A2 08 A0 
04 B9 CE C2 C9 05 30 05 69 02 99 CE C2 88 10 F1 A0 04 0E D3 C2 B9 CE C2 2A C9 
10 29 0F 99 CE C2 88 10 F2 CA D0 D9 C8 B9 CD C2 F0 FA 09 30 9D CD C2 E8 C8 C0 
06 F0 05 B9 CD C2 90 F0 A9 00 9D CD C2 60 85 0A A4 09 C0 00 F0 11 88 B9 D5 C2 
C5 0A D0 F4 8A D9 D5 C3 D0 EE 98 18 60 A4 09 E6 09 D0 01 60 A5 0A 99 D5 C2 8A 
99 D5 C3 98 99 D5 C4 18 60 A6 0B E4 09 30 01 60 BD D5 C5 C5 0B 30 09 A9 00 9D 
D5 C5 E6 0B D0 E9 A8 FE D5 C5 8A 29 01 D0 02 A0 00 BD D5 C4 59 D5 C4 9D D5 C4 
59 D5 C4 99 D5 C4 5D D5 C4 9D D5 C4 A9 00 85 0B 18 60 A8 A5 0C D0 08 A9 20 C5 
0D F0 21 A5 0C 8D 1E C2 8D 21 C2 A5 0D 09 60 8D 1F C2 49 E0 8D 22 C2 8C FF FF 
8E FF FF E6 0C D0 02 E6 0D 18 60 86 0E 84 0F A5 0D 09 60 8D 54 C2 49 E0 8D 5F 
C2 A6 0C CA E0 FF D0 10 AC 54 C2 88 C0 60 10 02 18 60 8C 54 C2 CE 5F C2 BD 00 
FF C5 0E F0 04 C5 0F D0 E0 BD 00 FF C5 0E F0 04 C5 0F D0 D5 38 60 A2 00 86 FC 
86 FD 86 FE BD D5 C4 A8 A6 FE E4 FC 10 11 BD D5 C7 AA 20 2B C2 90 14 E6 FE A6 
FE E4 FC D0 EF A6 FD BD D5 C4 A6 FC E6 FC 9D D5 C7 E6 FD A6 FD E4 09 D0 16 A6 
FB E4 FC 10 0F A2 00 BD D5 C7 9D D5 C6 E8 E4 FC D0 F5 86 FB 60 A0 00 84 FE F0 
B5

Demo online

Utilizzo: iniziare con sys49152, quindi inserire le coppie una per riga come ad es

15 1073
23 764
23 1073
12 47
47 15
1073 764

Backsapce non viene gestito durante l'input (ma se lo usivice , copia e incolla l'input nell'emulatore). Immettere una riga vuota per iniziare il calcolo.

È troppo grande per pubblicare un elenco di smontaggio esplicativo qui, ma è possibile sfogliare la fonte di assemblaggio in stile ca65 . L'algoritmo è molto inefficiente, genera ogni possibile permutazione dei nodi e con ognuno di questi costruisce avidamente una cricca controllando tutti i bordi. Ciò consente un'efficienza di spazio di O (n) (un po 'importante su una macchina con questa piccola RAM), ma ha un'orribile efficienza di runtime (*) . I limiti teorici sono fino a 256 nodi e fino a 8192 spigoli.

  • -71 byte: routine ottimizzata per il controllo dei bordi e dell'uso di zeropage

Esiste una versione più grande ( 883 805 byte) con funzionalità migliori:

  • feedback visivo durante il calcolo (ogni permutazione dei nodi cambia il colore del bordo)
  • utilizza il cambio di banco per memorizzare i bordi nella RAM "nascosti" dalle ROM per risparmiare spazio
  • genera la dimensione e i nodi della cricca massima trovata

Demo online

Sfoglia sorgente


(*) L'ultimo caso di test dura tra le 12 e le 20 ore (stavo dormendo alla fine). Gli altri casi di test terminano nel peggiore dei casi in pochi minuti.

Schermata dell'ultimo test case

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.