NPを実行する:最大のクリークを見つける


22

バックグラウンド

これを書いている時点で、NPの問題対Pは、まだ未解決のですが、聞いたことがあるかもしれませんノルベルト・ブルム社の新しい紙、すでにされてP!= NP、その主張を証明誤っていると疑われる(しかし、我々が表示されます)。

この論文で議論する問題はクリーク問題です。少なくとも新聞記事でそれを読んでいるので、間違っている場合は修正してください。しかし、いずれにしても、次のバリエーションを解決するプログラムを書いてほしいです。

タスク

たくさんの生徒がいる大きな学校があると仮定します。これらの各生徒には、この学校に何人かの友人がいます。生徒のクリークは、お互いのメンバーと友達である生徒だけから成るグループです。

あなたのプログラムは、入力として友人である学生のペアを受け取ります。この情報から、プログラムは最大のクリークのサイズを見つけなければなりません。学生は整数IDで識別されます。

数学用語を好む場合、これは、それぞれが2つのノードで識別される無向グラフのエッジを与えられることを意味します。

入力

入力は、正の整数ペアの空でないリストになります(例:)[[1,2],[2,5],[1,5]]。この入力は、たとえば、配列の配列、それぞれ2つの数値を含むテキスト行など、適切な形式で入力できます。

出力

予想される出力はn >= 2、最大のクリークのサイズである単一の数値です。上記の入力例で3は、すべての生徒(12および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. プログラムは、無効な入力に対して定義された結果を必要としません。だから、あなたはそれを仮定することができます:
    • 常に少なくとも1組のIDを取得ます
    • 各ペアは2つの異なるIDで構成されます
    • ペアは2回表示されません(IDの場所を入れ替えても同じペアになります)
  2. アルゴリズムでは、入力サイズの上限を設定できません。純粋に技術的な制限と言語/環境によって設定された制限(スタックサイズ、計算時間など)は、もちろん避けられません。
  3. 標準的な抜け穴は禁止されています。
  4. これはであるため、バイト単位で測定された最短のコードが優先されます。
  5. アルゴリズムが多項式時間の複雑さを持って-1いる場合、コードサイズに関係なくすぐにスコアリングしますが、その場合は、ソリューションを別の場所に送信することができます。;)

4
私はそれを行う(またはしようとする)誰かがいることをほぼ保証できるので、削除する方が安全です。人々に報酬を与えたい場合、多項式時間でそれを行う最短回答に報奨金を提供できます。
ケアニコインヘリンガー

4
@cairdcoinheringaahing誰かがやるなら、それ-1当然のことです;)
フェリックス

13
@cairdcoinheringaahing誰かがP = NPであると証明できた場合、コードゴルフの問題で自動的に最低スコアを獲得することは、私たちの関心事の少なくとも1つです。とはいえ、ルール5は実際にはこのチャレンジにあまり貢献していないため、削除する必要があることに同意します。
Mego

11
@Mego は、CMIが提供する1Mにジョークと小さなボーナスを提供するだけです。
フェリックスパルメン

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

Mathematica、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

-10バイトの@x Kelly Lowderに感謝


23
もちろん、Mathematicaにはこれが組み込まれています。
エリックアウトゴルファー

1
で10バイトをTr[1^#&@@FindClique[#<->#2&@@@#]]&
削る

12
FindCliqueಠ___ಠ
氏Xcoder

6

ゼリー、20バイト

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

オンラインでお試しください!

もちろん、これは百万に値するものではありません:p

ためていない場合、これは、ビートPythをしただろうµ(...)µし、2バイトÐf


すごい。私も今あきらめることがあります。
マークトーマス

@FelixPalmenブルートフォース:p
エリックアウトゴルファー

@EriktheOutgolfer私はコードの実行時間を意味しませんでした;)
Felix Palmen

P:私は意味@FelixPalmen、ブルートフォースアプローチは、多くの思考を必要としません
Outgolferエリック

与えMemoryErrorが最大のテストケースで:(もちろん、まだ有効なのは、これは「技術的な制限」である- ?しかし、ちょうど好奇心の、ゼリーで利用可能なリソースを増やす方法ですが
フェリックスPalmen

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変数に割り当てることで2バイトを保存できます
-shooqie

183バイト(x not in y)を意味し0**(x in y)ます。
ミスターXcoder

@ Mr.Xcoder短縮する方法があることは知っていました!ありがとう!
エリックアウトゴルファー

私はこれを使用したことがありません。数日前に頭をよぎっただけで、まだ使用方法が見つかりませんでした。
ミスターXcoder

@ Mr.Xcoderは重要ではありませんが、それが機能する場合、なぜそうではないのですか?:Dところであなたも置き換えることができ0**-~-
エリックアウトゴルファー

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

Pythonの3162の 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の最後のテストケースの時間を超過

更新:「or(z、y)in x」の部分が追加され、itertools.chainセットではなく、sortedness「f = lambda x:{i for s in x for i in s}」への依存性がなくなりました。

-マイナス3バイト、@ Jonathan Allenのおかげ



別に-あなたは名前にする必要はありませんcので、削除することができ、c=(あなたが配置する必要があると思いc=\ヘッダの終わりと置かlambdaTIOのためのコードブロックの先頭に)
ジョナサン・アラン

また、あなたはを取り除くことができますsし、交換するs(...){*...}、あまりにもいくつかのスペースの除去が可能。
ジョナサンアラン

1
@ジョナサンアランのおかげで、ソートの修正
コナー・ジョンストン


1

ゼリー、28バイト

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

オンラインでお試しください!

TIOで最後のテストケースを1秒で解決できる、より高速なソリューション。


そして、これにはどのような複雑さがありますか?O(2ⁿ)より低い場合は、$ 1,000,000に値します。
エリックアウトゴルファー

1
@EriktheOutgolfer、あなたは間違っています、O(1.1888ⁿ)ランタイムを持つアルゴリズムがあります。
rus9384

それに加えて、100万の価値があるためn、ベースにのみ表示される場合があります:)
フェリックスパルメン

@FelixPalmen、またはそれはできません。とにかく、百万のために2つの声明の1つが証明されなければなりません。
rus9384

1
これはO(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メソッドとtool-collection-typeを使用し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にあまり慣れていません:)
Felix Palmen

@FelixPalmen私はこのチャレンジが好きだったので、私の答えは何があっても変わらないが、多項式の複雑さでなければ「-1」を削除しても大丈夫だ。その後、私はおそらくいくつかの本を見直して行く必要があります:P
オリヴィエ・グレゴワール

サイズの組み合わせxは多項式」<-確かですか?私はそれが使用される方法だと思います。戻り値はAbstractSet、イテレータとし、次のforループでは、このイテレータ呼ぶx!私は間違っていない場合は...回
フェリックスPalmen

訂正:長いほどx < n(とn入力セットの完全なサイズである)、それだn!/(x!(n-x)!)、まだない多項式:)
フェリックスPalmen

@FelixPalmenあなたはおそらく正しいでしょう。また、(完全に可能な)combinationsメソッドを作成すればX^n、それを取得できると言っていますか?一方、「-1」の主張を削除します。
オリビエグレゴワール


0

6502マシンコード(C64)、774 703バイト

(私はこれをしなければならなかった、私のC64はすべてを行うことができます... 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

オンラインデモ

使用法:で始まりsys49152、次のように行ごとにペアを入力します

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

Backsapce 入力中に処理されません(ただし、を使用する場合はvice、入力をコピーしてエミュレータに貼り付けてください)。空行を入力して計算を開始します。

これは大きすぎて説明的な逆アセンブリリストをここに投稿することはできませんが、ca65スタイルのアセンブリソースを参照できます。このアルゴリズムは非常に非効率的であり、ノードのあらゆる可能な順列を生成し、これらのそれぞれがすべてのエッジをチェックすることによりクリークを構築します。これにより、O(n)のスペース効率この小さなRAMを搭載したマシンでは重要が可能になりますが、実行時の効率は非常に低くなり ます (*)。理論上の制限は、最大256ノードおよび最大8192エッジです。

  • -71バイト:エッジとゼロページの使用をチェックするための最適化されたルーチン

より優れた機能を備えたより大きなバージョン(883 805バイト)があります。

  • 計算中の視覚的なフィードバック(ノードの置換ごとに境界線の色が変わります)
  • バンクスイッチングを使用して、ROMによって「隠された」RAMにエッジを保存し、スペースを節約します。
  • 見つかった最大クリークのサイズノードを出力します

オンラインデモ

ソースを閲覧


(*)最後のテストケースには12〜20時間かかります(最終的に終了したとき、私は寝ていました)。他のテストケースは、数分以内に最悪の状態で終了します。

最後のテストケースのスクリーンショット

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.