Зробіть NP: знайдіть найбільшу кліку


22

Фон

На момент написання цього завдання проблема P vs NP все ще не вирішена, але ви, можливо, чули про нову книгу Норберта Блума, яка стверджує доказ того, що P! = NP, який, як підозрюється, є помилковим (але ми побачимо).

Проблема, обговорювана в цій роботі, - проблема кліку . Принаймні, це я читав у газетній статті, тож виправте мене, якщо я помиляюся, але в будь-якому випадку я хотів би, щоб ви написали програму, яка вирішує наступний варіант:

Завдання

Припустимо, у нас є велика школа з великою кількістю учнів. У кожного з цих учнів є кілька друзів у цій школі. Кліка студентів є група , що складається тільки з студентів , які є друзями з кожним іншим членом .

Ваша програма прийме пари студентів, які є друзями як її вклад. З цієї інформації програма повинна знайти розмір найбільшої кліки . Студенти ідентифікуються за цілими ідентифікаторами .

Якщо ви віддаєте перевагу математичним термінам, це означає, що вам подано краї ненаправленого графіка, позначені двома вузлами кожен.

Вхідні дані

Ваш вхід буде не порожнім списком позитивних цілих пар, наприклад [[1,2],[2,5],[1,5]]. Ви можете приймати цей ввід у будь-якій розумній формі, наприклад, як масив масивів, як рядки тексту, що містять по два числа кожен, і т. Д. ...

Вихідні дані

Очікуваний вихід - це одне число n >= 2: розмір найбільшої кліки. У прикладі , вхід вище, результат буде 3, як і всі студенти ( 1, 2і 5) є друзями один з одним.

Тестові кейси

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

Ви можете використовувати цю (дурну) довідкову реалізацію (друкує додатковий вихід із -dпрапором) для перевірки результатів інших тестових випадків.

Правила

  1. Вашій програмі не потрібен визначений результат щодо недійсного введення. Тож можна припустити, що:
    • ви завжди отримаєте принаймні одну пару ідентифікаторів
    • кожна пара складається з двох різних ідентифікаторів
    • жодна пара не з’являється двічі (поміняти місцями ідентифікаторів все одно буде одна і та ж пара)
  2. Вашому алгоритму заборонено встановлювати верхню межу розміру вводу. Звичайно, технічні обмеження та обмеження, встановлені вашою мовою / середовищем (наприклад, розмір стека, час обчислення тощо), звичайно, неминучі.
  3. Стандартні лазівки заборонені.
  4. Це , тому найкоротший код, виміряний в байтах, виграє.
  5. Якщо ваш алгоритм має складну багаточленну часову складність, ви отримуєте бал -1негайно, незалежно від розміру коду, але в цьому випадку ви можете подати рішення десь в іншому місці. ;)

4
Я майже можу гарантувати, що знайдеться хтось, хто це зробить (або спробує), тому просто видалити його було б безпечніше. Якщо ви хочете нагородити людей за це, ви можете запропонувати винагороду за найкоротшу відповідь, яка робить це в поліноміальний час.
caird coinheringaahing

4
@cairdcoinheringaahing якщо хто - то робить це, -1є заслуженим ;)
Фелікс Palmen

13
@cairdcoinheringaahing Якщо комусь вдалося довести, що P = NP, вони мають автоматичну найнижчу оцінку на проблему з гольфовим кодом - це найменша проблема. Однак, правило 5 не дуже сприяє виклику, тому я погоджуюся з тим, що його слід усунути.
Мего

11
@Mego це просто сприяє жарту і крихітному бонусу до 1М, пропонованого CMI.
Фелікс Палмен

30
Ну, я не буду на користь небагатьох людей, які мають певне почуття "наукового гумору". Будь ласка, не коментуйте більше пропозицій щодо цього, дякую :)
Фелікс Палмен

Відповіді:


6

Желе ,  15 18  16 байт

+3 байти, щоб виправити помилки в моєму методі.
-2 байти завдяки милям (зауваживши, що n × (n-1) ÷ 2 = nC2 )

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

Монадійне посилання, що бере список дружби (ребер) і повертає ціле число.

Спробуйте в Інтернеті! формує енергетичний набір країв пам'яті, тому неефективний як у просторі, так і в часі (так, це O (2 n ) люди)!

Як?

Ẏ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

Вау, пояснення, коли у вас є час
містер Xcoder

@EriktheOutgolfer Я згоден. Я, напевно, можу додати код до пошкодження ...
Джонатан Аллан



@miles - приємно, я просто витратив деякий час, намагаючись отримати 15 з цього, я відчуваю, що це має бути можливо!
Джонатан Аллан

13

Математика, 34 байти

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

В основному FindClique виконує завдання і "знаходить найбільшу кліку в графі g".
Усі інші речі - це перетворення вхідного списку в графік

Вхідні дані

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

Вихідні дані

4

Вхідні дані

[{{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

thanx @Kelly Lowder на -10 байт


23
Звичайно, Mathematica має для цього вбудований.
Erik the Outgolfer

1
Поголіть 10 байт зTr[1^#&@@FindClique[#<->#2&@@@#]]&
Келлі Лоудер

12
FindCliqueಠ ___ ಠ
Містер Xcoder

6

Желе , 20 байт

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

Спробуйте в Інтернеті!

Звичайно, цього мільйона не заслуговує: с

Це би перемогло Pyth, якби не µ(...)µ2-байт Ðf.


Дивовижний. Я також можу зараз відмовитись.
Марк Томас

@FelixPalmen brute force: p
Erik the Outgolfer

@EriktheOutgolfer Я не мав на увазі час виконання коду;)
Фелікс Палмен

@FelixPalmen Я маю на увазі, грубий підхід не потребує особливих роздумів: p
Ерік the Outgolfer

Надає MemoryError з найбільшим тестовим випадком :( Звичайно, це все-таки дійсно, це "технічне обмеження" - але просто з цікавості, чи є спосіб збільшити наявні ресурси за допомогою желе?
Фелікс Палмен

3

J , 36 байт

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

Спробуйте в Інтернеті!

Працює в часі O (2 n ), де n - кількість пар.

Більш швидке рішення на 65 байт

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

Спробуйте в Інтернеті!

Пояснення

[:>./](#(]*[=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 байт

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

Спробуйте в Інтернеті!

-2 завдяки shooqie .
-1 дякую містеру Xcoder .
-3 завдяки рекурсивному .


Ви можете зберегти два байти, призначивши lenзмінну
shooqie

183 байти . (x not in y)засоби 0**(x in y).
Містер Xcoder

@ Mr.Xcoder Я знав, що існує спосіб скоротити його! Спасибі!
Erik the Outgolfer

Я ніколи цього не використовував, просто хитрість, яка перекреслила мою думку пару днів тому, але поки не могла знайти для цього користь.
Містер Xcoder

@ Mr.Xcoder Не має значення, якщо це працює, то чому б ні? : D речі ви можете замінити 0**з -~-.
Erik the Outgolfer

1

Pyth, 28 байт

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

Спробуйте в Інтернеті

Пояснення

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

Пітон 3 , 162 159 байт

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)

Спробуйте в Інтернеті!

Функція c приймає вершини у вигляді набору відсортованих кортежів ({(x, y), ...}, де x менше y). Функція під назвою "запис" знаходиться у заголовку TIO для перевірки даних у списку неортизованого формату списків . Якщо кліка, повертає довжину. Якщо не клика, повертає максимальний розмір кліку вершин, мінус вершину для кожної вершини у вершинах. Перевищує час останнього тестового випадку в TIO

Оновлення: "або (z, y) у x" додано для усунення залежності від сортування "f = лямбда x: {i для s в х для i в s}" замість itertools.chain, загорнутого в набір.

-minus 3 байти завдяки @Jonathan Allen



Убік - вам не потрібно називати імена c, тому можете видалити c=(вам потрібно поставити c=\в кінці заголовка і розмістити lambdaвгорі блоку коду для TIO)
Джонатан Аллан

Також ви можете позбутися відs і замінити s(...)з {*...}дозволяючи видалення деяких просторів теж.
Джонатан Аллан

1
@JonathanAllan дякую, сортуваність виправлена
Коннер Джонстон


1

Желе , 28 байт

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

Спробуйте в Інтернеті!

Швидше рішення, яке здатне вирішити останній тестовий випадок за секунду на TIO.


І яку складність це має? Якщо це щось нижче, ніж O (2ⁿ), то він заслуговує 1 000 000 доларів.
Ерік Аутгольфер

1
@EriktheOutgolfer, ви неправі, є алгоритми, які мають O (1.1888ⁿ) час виконання.
rus9384

Додавши до цього, що коштуватиме мільйон, вони nможуть з’явитися лише в базах :)
Фелікс Палмен

@FelixPalmen, або це не може. У будь-якому випадку, для мільйона одна з двох заяв повинна бути доведена.
rus9384

1
Я вважаю, що це О (1.414 ^ n). Ви можете бачити гірші показники, коли вхід є повним графіком.
миль

1

Java + Guava 23,0, 35 + 294 = 329 байт

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

Цей алгоритм не є графічним, а натомість генерує всі комбінації пар певного розміру. Я подаю всі парні комбінації в мультисети і перевіряю, чи всі вони мають очікуваний розмір (кількість унікальних записів - 1). Якщо вони є, я знайшов кліку і йду шукати більшу.

З бібліотеки Guava я використовую новий combinationsметод та тип колекції інструментів Multiset.

Безумовно

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

Я був би дуже здивований, див. Як знайти максимальну кількість кліків у довільних графах - але мені знадобиться певний час, щоб проаналізувати цей код, я не надто знайомий з Java :)
Фелікс Палмен,

@FelixPalmen Мені сподобався цей виклик, тому моя відповідь залишатиметься незважаючи ні на що, але я повністю гаразд з видаленням "-1", якщо це не поліноміальна складність. Тоді я, мабуть, мушу переглянути деякі книги: Р
Олів'є Грегоар

" Поєднання розміру xє поліном " <- ви впевнені? Я думаю, що це метод, який використовується . Повернене значення - це AbstractSetітератор, і наступний forцикл буде називати цей ітератор x!раз, якщо я не помиляюся ...
Фелікс Палмен

Виправлення: до тих пір, поки x < nnповним розміром вхідного набору), воно n!/(x!(n-x)!)все ще не є многочленом :)
Фелікс Палмен

@FelixPalmen Ви, швидше за все, маєте рацію. Крім того, ви кажете, що якщо я зробив такий combinationsметод X^n(який цілком можливий), я можу його отримати? Тим часом я знімаю свою заяву про "-1".
Олів’є Грегоар


0

Машинний код 6502 (C64), 774 703 байт

(Я просто повинен був це зробити, мій C64 може все робити ... хе-хе)

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

Демонстрація в Інтернеті

Використання: Почніть з sys49152, а потім введіть пари по одному рядку, наприклад,

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

Під час введення даних Backsapce не обробляється (але якщо ви використовуєте vice, просто скопіюйте та вставте вхід в емулятор). Введіть порожній рядок, щоб почати обчислення.

Це занадто велика кількість, щоб розмістити тут пояснювальний список розбирання, але ви можете переглянути джерело збірки в стилі ca65 . Алгоритм дуже неефективний, він генерує всі можливі перестановки вузлів і з кожним із них жадібно будує кліку, перевіряючи всі ребра. Це дозволяє простір ефективності з O (N) (вид важливо на машині з цим маленьким ОЗУ), але має жахливу ефективність виконання (*) . Теоретичні межі - до 256 вузлів і до 8192 ребер.

  • -71 байт: оптимізована програма для перевірки використання країв та нульової сторінки

Є більша ( 883 805 байт) версія з кращими можливостями:

  • візуальний зворотний зв'язок під час обчислення (кожна перестановка вузлів змінює колір межі)
  • використовує комутацію банку для зберігання країв ОЗУ, «захованих» ПЗУ, щоб заощадити простір
  • виводить розмір та вузли максимальної знайденої кліки

Демонстрація в Інтернеті

Переглянути джерело


(*) Останній тестовий випадок займає приблизно від 12 до 20 годин (я спав, коли він остаточно закінчився). Інші тестові справи закінчуються в гіршому випадку протягом декількох хвилин.

Скріншот останнього тестового випадку

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.