做NP:找到最大的集团


22

背景

在撰写本文时,P与NP的问题仍未解决,但是您可能已经听说过Norbert Blum的新论文,声称P!= NP已证明是错误的(但我们将会看到)。

本文讨论的问题是集团问题。至少这是我在报纸上读到的,如果我错了,请更正我,但是无论如何,我希望您编写一个解决以下变体的程序:

任务

假设我们有一所大学校,有很多学生。每个学生在这所学校都有一些朋友。一个集团的学生是仅由学生谁是朋友与一组的每个其他成员

您的程序将接收成对的朋友,作为他们的输入。从这些信息中,程序必须找到最大的集团的规模。学生用整数ID标识

如果您更喜欢数学术语,这意味着您将获得一个无向图的边缘,该边缘分别由两个节点标识。

输入项

您的输入将是一个正整数对的非空列表,例如[[1,2],[2,5],[1,5]]。您可以采用任何明智的形式来输入此输入,例如,作为数组的数组,作为文本行,每个文本行包含两个数字,等等...

输出量

预期的输出是一个数字n >= 2:最大集团的规模。与上面的例子中的输入,其结果将是3,因为所有的学生(125)是朋友彼此。

测试用例

[[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. 您的程序不需要输入无效的已定义结果。因此,您可以假设:
    • 您将始终获得至少一对 ID
    • 每对包含两个不同的ID
    • 没有对出现两次(交换ID的位置仍是同一对)
  2. 您的算法不允许设置输入大小的上限。当然,纯粹的技术限制和由您的语言/环境设置的限制(例如堆栈大小,计算时间等)是不可避免的。
  3. 禁止出现标准漏洞。
  4. 这是,因此以字节为单位的最短代码胜出。
  5. 如果您的算法具有多项式时间复杂度,则-1无论代码大小如何,您都可以立即评分,但是在这种情况下,您可能希望将解决方案提交到其他地方。;)

4
我几乎可以保证会有(或尝试)这样做的人,因此将其删除会更安全。如果您想奖励这样做的人,则可以对多项式时间最短的答案提供赏金
caird coinheringaahing

4
@cairdcoinheringaahing如果有人这样做,那-1当之无愧的 ;)
Felix Palmen '17

13
@cairdcoinheringaahing如果有人设法证明P = NP,那么他们在代码高尔夫问题上的自动最低分就是我们关注的最少的问题。就是说,规则5并未真正对挑战做出太大贡献,因此我同意应将其删除。
Mego

11
@Mego它只是为CMI提供的1M提供了一个笑话和微不足道的奖励。
菲利克斯·帕尔姆

30
好吧,我不会支持少数具有某种“科学幽默”感的人。请不要对此发表更多建议,谢谢:)
Felix Palmen

Answers:


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我同意。我可能可以在打捞中添加代码...
Jonathan Allan



@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

thanx @Kelly Lowder -10个字节


23
当然,Mathematica对此具有内置功能。
暴民埃里克(Erik the Outgolfer)'17年

1
Tr[1^#&@@FindClique[#<->#2&@@@#]]&
Kelly Lowder删除

12
FindCliqueಠ___ಠ
Xcoder先生

6

果冻,20字节

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

在线尝试!

当然,这不值得百万:p

如果不是µ(...)µand和2字节,这将击败Pyth Ðf


惊人。我现在最好放弃。
马克·托马斯

@FelixPalmen蛮力:p
暴民埃里克(Erik the Outgolfer)

@EriktheOutgolfer我并不是说代码的运行时;)
Felix Palmen '17

@FelixPalmen我的意思是,蛮力方法不需要太多思考:p
暴民埃里克(Erik the Outgolfer)

给出一个带有最大测试用例的MemoryError :(当然仍然有效,这是一个“技术限制”-但出于好奇,是否有办法增加果冻的可用资源?
Felix 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变量来节省两个字节
shooqie

183个字节(x not in y)意味着0**(x in y)
Xcoder先生17年

@ Mr.Xcoder我知道有一种方法可以缩短它!谢谢!
暴民埃里克(Erik the Outgolfer)'17年

我以前从未使用过它,只是几天前我脑子里突然想起的一个把戏,但还没有找到用。
Xcoder先生17年

@ Mr.Xcoder没关系,如果可以,为什么不呢?:D BTW您也可以替换0**-~-
暴民埃里克(Erik the Outgolfer)'17年

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 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标头中有一个名为“ entry”的函数,用于对未排序列表格式的列表中的数据进行测试。如果是集团,则返回长度。如果不是集团,则返回顶点的最大集团大小,减去顶点中每个顶点的一个顶点。在TIO中超过最后一个测试用例的时间

更新:“或在x中添加了(或(z,y)”)以消除对排序的依赖性“ f = lambda x:{i for s in x for in in s}}”,而不是包裹在set中的itertools.chain。

-减去3个字节,感谢@Jonathan Allen



除了-您不需要命名c,因此可以删除c=(您需要将其放在c=\标题的末尾,并将其lambda放在TIO的代码块的顶部)
Jonathan Allan

此外,你可以摆脱s和替换s(...){*...}允许去除一些空间了。
乔纳森·艾伦,

1
@JonathanAllan感谢,有序性固定
康纳约翰斯顿


1

果冻,28个字节

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

在线尝试!

更快的解决方案,能够在TIO上每秒解决最后一个测试用例。


这有什么复杂性?如果它小于O(2ⁿ),则应获得$ 1,000,000。
暴民埃里克(Erik the Outgolfer)

1
@EriktheOutgolfer,您错了,有些算法具有O(1.1888ⁿ)运行时。
rus9384 '17

除此之外,价值一百万,n可能只出现在基准中:)
Felix Palmen '17

@FelixPalmen,否则不能。无论如何,对于百万,必须证明两个陈述之一。
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
OlivierGrégoire'17

大小组合x是多项式 ” <-确定吗?我想这就是使用的方法。返回值是一个AbstractSet带有迭代器的值,如果我没记错的话,以下for循环将调用此迭代器x!时间...
Felix Palmen

更正:只要x < n(与n输入集的完整大小一样),它n!/(x!(n-x)!)仍然是,而不是多项式:)
Felix Palmen

@FelixPalmen您最正确。另外,你说,如果我做combinations这方法X^n(这是完全有可能的),我可以得到它?同时,我删除了对“ -1”的要求。
奥利维尔·格雷戈尔


0

6502机器代码(C64),774703字节

(我不得不这样做,我的C64可以做的一切......嘿嘿)

十六进制转储:

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字节)版本,具有更好的功能:

  • 计算过程中的视觉反馈(节点的每个置换都会更改边框颜色)
  • 使用存储区切换将边缘存储在ROM“隐藏”的RAM中以节省空间
  • 输出找到的最大集团的大小节点

在线演示

浏览源


(*)最后一个测试用例需要12到20个小时(最终完成时我正在睡觉)。其他测试用例在几分钟之内最坏的情况下完成。

最后一个测试用例的屏幕截图

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.