我们应该成为朋友吗?


30

请注意,这是一个主要关注

介绍

Bacefook希望人们变得更加友好!因此,他们正在实施一个新系统来推荐朋友!您的任务是帮助Bacefook实施新的建议系统。

规格:

你的程序必须是支持3种类型的命令的一个REPL(读取-求值-输出循环): FRIENDSUGGESTKNOW

FRIEND X Y-指定XY是社交网络中的朋友。

  • 如果X是Y的朋友,那么Y是X的朋友

  • 可以,但不必输出

  • X永远是X的朋友

KNOW X Y -如果X和Y是朋友,则输出真实值,否则输出虚假值

  • KNOW X X 将始终输出真实值

SUGGEST X Y-如果X和Y应该是朋友,则输出真实值,否则输出虚假值。如果满足以下条件,则X和Y应该是朋友:

  • X和Y不是朋友

  • X和Y至少有1个共同的朋友

你被允许代替FRIENDSUGGESTKNOW用自己的字符串,但你必须谈不上什么串您更换每个命令。

您的程序可以以任何希望的方式接受输入/产生输出,只要可以相当容易地识别其工作方式即可。

社交网络中的人数N在1到100,000之间,但是可能有任意数量的“朋友链接”(边缘)。

如果您尚未注意到,这是一个图形搜索问题。实现此功能的(可能)最简单(可能最快)的数据结构将是邻接矩阵。

测试用例

FRIEND A B
FRIEND A C
FRIEND B D
SUGGEST A B -> Falsy, as they are friends
SUGGEST A D -> Truthy, as they share B as a common friend
SUGGEST C D -> Falsy, they do not share a common friend
KNOW D B -> Truthy, they are friends
KNOW B C -> Falsy, not friends
=============
FRIEND Tom Tim
KNOW Tom Tim -> Truthy
KNOW Tim Tom -> Truthy
KNOW Tom Kit -> Falsy
=============
KNOW Tim Kit -> Falsy
FRIEND Tim Tom
KNOW Tim Kit -> Falsy
FRIEND Tom Kit
SUGGEST Tim Kit -> Truthy
=============
FRIEND X Y
SUGGEST X Y -> Falsy since X is friends with X

这是图像形式的更多测试用例

获胜条件

这是,最短的代码获胜!


因此,例如,我们可以从输入网络中所有人的列表开始{A, B, C, D}吗?
格雷格·马丁

2
用文本形式的测试用例会更有帮助。
格雷格·马丁

1
在FRIEND命令之后可以输出吗?
ovs'Mar

7
SUGGEST UK EU
WBT

1
在Python中,@ Thunda使用内置的REPL在命令中需要两个额外的字符。这样的语言是否应该将这些额外的字节添加到程序的总长度中?
quintopia's

Answers:


44

SWI-Prolog,62 47 41字节

X*Y:-X+Y;Y+X;X==Y.
X?Y:-not(X*Y),X*Z,Y*Z.

Prolog并不是很有用,但是当它很漂亮的时候。我们将使用a+b谱写那a是朋友ba*ba知道ba?b认为b应建议a与否。第一行简单说,X*Y就是如果为true要么X+YY+X或者X == Y是真实的。这实现了彼此了解的对称性。询问是否应该提出建议非常简单。我们只询问是否有Z这样X*Y是假的X*Z,并Y*Z是真实的。完全如挑战中所述。

如果将其另存为文件(例如friends.pl),并使用该文件(prolog -l friends.pl)打开SWI-Prolog,则将您放入REPL。

您可以这样维护友谊:

assert('a' + 'b').
assert('a' + 'c').
assert('b' + 'd').

您可以检查人们是否认识彼此或提出建议:

'a'*'b'.
'a'?'d'.

您应该能够保存一堆字节,用和替换k(X,Y)X*Yfs使用不同的操作数。如果正确计数,则为21个字节。
Emigna

虽然不确定它们如何与asserts一起工作,所以我不确定f
Emigna

12
通过问题的数据结构设计部分完全放屁。惊人。
桑达

@Emigna我已经实现了它,但是它没有像您计算的那样节省很多。
Orlp

我测试像这样在41个字节。我没有REPL可以尝试,所以我不知道它在这里是否有所不同。
Emigna

15

PHP,138个133 129字节

PHP击败了Mathematica-一种罕见的情况。

for(;$s=fgets(STDIN);$s>G?print$$a[$b]?$s<L:$s>L&&@array_intersect_key($$a,$$b):$$a[$b]=$$b[$a]=1)[,$a,$b]=explode(" ",trim($s));

打印1为真,虚假为空字符串。在线运行-nr或对其进行测试
需要PHP 7.1进行列表分配;用户名是大小写敏感的,应排除abs

分解

for(;$s=fgets(STDIN);                       # loop through input
    $s>G                                        # 2. evaluate command
        ?print$$a[$b]
            # command KNOW: true if $$a[$b]
            ?$s<L
            # command SUGGEST: true if !$$a[$b] and array_intersect_key returns truthy
            :$s>L&&@array_intersect_key($$a,$$b)
        # command FRIEND: set keys in $$a and $$b
        :$$a[$b]=$$b[$a]=1
)
    [,$a,$b]=explode(" ",trim($s));             # 1. parse user names to $a and $b
  • $s 必须修剪,因为它包含换行符。
  • array_intersect_key必须静音,否则会发出空$$a或警告的警告$$b
  • +18 +15字节的所有用户名:更换$$a$f[$a]$$b$f[$b]

12

CMD(批量),50 + 20 + 135 = 205字节

  • 朋友

    @for %%f in (%1.%1 %1.%2 %2.%2 %2.%1)do @set %%f=1
    
  • 知道CMD

    @call echo(%%%1.%2%%
    

    1为朋友打印,为陌生人打印空白行。

  • 建议

    @call set k=0%%%1.%2%%
    @set k=1&if %k%==0 for /f "tokens=2 delims=.=" %%f in ('set %1.')do @call set k=%%k%%%%%%f.%2%%
    @echo(%k:~1,1%
    

    打印1或空白行。我认为连续六个%秒可能是新的个人最好成绩。


太棒了。不错的解决方案。
AdmBorkBork

6

Python 3,122 118 + 2 = 120字节

l={}
def f(*r):l[r]=l[r[::-1]]=1
k=lambda a,b:a==b or(a,b)in l
s=lambda a,b:1-k(a,b)and any(k(a,z)&k(b,z)for z,_ in l)

用法与ovs的答案完全相同。


1
这对我来说很明显,但是要求说您需要指定如何使用REPL以及使用哪些命令。对于不懂python的人可能有用。(顺便说一句,这正是我会使用的方法。)
quintopia

6

Python 3中,163 149 143 + 2 = 145个字节

-6个字节,感谢@FelipeNardiBatista

l=[]
def f(a,b):l.extend([(a,b),(b,a)])
k=lambda a,b:a==b or(a,b)in l
s=lambda a,b:k(a,b)-1and{c for c,d in l if d==a}&{c for c,d in l if d==b}

将其保存到文件并以python3 -i file.py
使用
- f("a", "b")代替FRIENDS a b
- k("a", "b")代替KNOW a b
- s("a", "b")代替-运行SUGGEST a b

Falsey输出:0,set(),False
Truth输出:非空set,True

在线尝试


不使用python解释器作为REPL时为164个字节:

f=[]
while 1:c,a,b=input().split();i=(a,b)in f;f+=c=="f"and[(a,b),(b,a)]or[(i+(a==b),-i+1and{c for c,d in f if d==a}&{c for c,d in f if d==b})];print(f[-1][c=="s"])

用于
- f用于FRIEND
- s用于SUGGEST
-其他任何用途KNOW

在线尝试


对于第二个链接,建议功能已损坏
Thunda

@Thunda修复了问题
ovs'Mar

如果我缺少某些东西,请指正我,但是l.extend([(a,b),(b,a)])可以,不是l+=[(a,b),(b,a)]吗?(我尚未对此进行测试)
HyperNeutrino

抱歉,我意识到我的错误导致了UnboundLocalError。好的答案!
HyperNeutrino

如果您删除bool()s功能和使用0{}False作为Falsey和True和不空set为Truthy,你可以保存6个字节
菲利普·纳迪巴蒂斯塔

5

Mathematica,164个字节

f={}
p:=Union@@f
i=Position[p,#][[1,1]]&
m:=Outer[Boole@MemberQ[f,{##}]&,p,p]
a=(#[[i@#2,i@#3]]/._@__->0)>0&
F=(f=#~Tuples~2~Join~f;)&
K=m~a~##&
S=a[m.m,##]&&!K@##&

定义三个主要功能FSK具有所需的行为。例如,命令序列

F@{David, Bob}
F@{Bob, Alex}
F@{Alex, Kitty}
F@{Daniel, David}
F@{David, Kit}
S[David, Alex]
S[Bob, Kitty]
S[David, Kitty]
S[David, Bob]
K[David, Bob]
F@{Kit, Kitty}
S[David, Kitty]

是OP中链接的映像中的最后一个测试用例;该F命令产生任何输出(单分号似乎是一个很小的代价为这个),而6个SK命令产量

True
True
False
False
True
True

如预期的。

在任何时刻,f是有序对形式的列表{A, B},其中A知道B,虽然p是出现在一些元素人名单f。调用F@{A, B}增加了四个有序对{A, B}{B, A}{A, A},和{B, B}f

而且,在任何时候,m基础图都是邻接矩阵(一个人与自己及其所有朋友都相邻F);行和列由索引pi并将一个人转换为相应的行/列号。helper函数a将一个矩阵和两个人作为输入,并查找其“坐标”为两个人的矩阵的条目,True如果数字为正,False如果为零,则返回。(也可以在a尚未识别输入人之一的情况下进行调用,例如,在任何FRIEND声明之前进行KNOW或SUGGEST查询,或询问一些没有朋友的可怜人;这会引发错误,但是规则/._@__->0强制输出False仍然是。)

K[A, B]因此,Calling 查找是否m[A, B]为正,从而实现了K现在的动词。矩阵乘积m.m是长度2路径矩阵,包含从一个人到另一个人沿长度2的路径的方法数量;只要我们另外手动检查()输入的人彼此之间还不认识,就S[A, B]可以实现最S粗略的动词&&!K@##

有趣的事实:自由,这实现使我们申报拉帮结派朋友-命令F@{A, B, C, D}等同于所有的F@{A, B}F@{A, C}F@{A, D}F@{B, C}F@{B, D},和F@{C, D}结合。


2

Python 2,118字节

F=[]
def s(f,c):c=set(c);r=c in F;return F.append(c)if f%2 else not r^(4 in[len(x|c)for x in F])if f else 2>len(c)or r

在线尝试!

由于找不到python 2的repl在线工具,因此我添加了TIO Nexus(采用REPL格式)。

查询选项及其可能的输出

0为已知-无

1个给好友-对或错

2个建议-对或错

在repl python解释器中的用法示例和示例输出。

>>> F=[]
>>> def s(f,c):c=set(c);r=c in F;return F.append(c)if f%2 else not r^(4 in[len(x|c)for x in F])if f else 2>len(c)or r
...
>>> s(1,['A','B'])
>>> s(1,['A','C'])
>>> s(1,['B','D'])
>>> s(2,['A','B'])
False
>>> s(2,['A','D'])
True
>>> s(2,['C','D'])
False
>>> s(0,['D','B'])
True
>>> s(0,['D','C'])
False

0

GNU sed 158 + 2(rn个标志)= 160个字节

由于sed是基于正则表达式的语言,因此没有原始类型,更不用说抽象数据结构了。网络数据存储为自由格式的文本,在这种情况下,存储为诸如类似的冗余朋友链接A-B;B-A;,然后将其与各种正则表达式模式进行匹配。

G
/^F/{s:. (.+) (.+)\n:\1-\1;\1-\2;\2-\1;\2-\2;:;h}
/^K |^S /{s:(.) (.+) (.+)\n.*\2-\3.*:\1:;/^K$/p}
/^S /s:(.) (.+) (.+)\n.*(.+)-(\2.*\4-\3|\3.*\4-\2).*:\1:p

在线尝试!

按照设计,sed为每个输入行运行整个脚本。我建议以交互模式进行测试,以便在键入后立即查看命令的输出。

用法: sed中没有真值/虚假值,因此我使用的输出约定是从bash借来的,因此,非空字符串被视为真值,而空字符串被视为虚假。

  • F X YFRIEND X Y。没有输出。
  • K X YKNOW X Y。输出“ K”为真实,而没有输出为“虚假”。
  • S X YSUGGEST X Y。输出'S'为真实,而没有输出为虚假。

说明:

G
# append stored network data, if any, to the current input line
/^F/{
# if command is 'F' (FRIEND), for ex. 'F X Y'
   s:. (.+) (.+)\n:\1-\1;\1-\2;\2-\1;\2-\2;:
   # generate friend links, for ex. 'X-X;X-Y;Y-X;Y-Y'
   h
   # store updated network data
}
/^K |^S /{
# if command is either 'K' (KNOW) or 'S' (SUGGEST), for ex. 'K X Y'
   s:(.) (.+) (.+)\n.*\2-\3.*:\1:
   # search friend link 'X-Y'. If found, delete pattern except the command letter.
   /^K$/p
   # if only letter K left, print it (command is 'K', 'X' and 'Y' are friends)
}
/^S /
# if command is 'S', for ex. 'S X Y', but 'X' and 'Y' aren't friends
   s:(.) (.+) (.+)\n.*(.+)-(\2.*\4-\3|\3.*\4-\2).*:\1:p
   # search if 'X' and 'Y' have a friend in common (for ex. 'C'), and if so print
   #letter S. The search is for ex. 'C-X.*C-Y' and 'C-Y.*C-X'.
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.