Arkadaş olalım mı


30

Bu, öncelikle odaklanan bir soru olduğuna dikkat edin

Giriş

Bacefook insanların dostça olmasını istiyor! Bu nedenle, arkadaş önermek için yeni bir sistem uyguluyorlar! Göreviniz Bacefook'a yeni önerme sistemlerini uygulamalarında yardımcı olmak.

Özellikler:

Programınız komuta 3 tip destekleyen bir REPL (okuma-eval-baskı döngü) olması gerekir: FRIEND, SUGGESTve KNOW.

FRIEND X Y- Bunu belirtir Xve Ysosyal ağda arkadaşlar.

  • Eğer X Y ile arkadaşsa, Y X ile arkadaş

  • Olabilir, ancak çıktısı olması gerekmiyor

  • X her zaman X ile arkadaş

KNOW X Y - Eğer X ve Y arkadaşlar ise, gerçek olmayan bir değer verir, aksi takdirde sahte olur

  • KNOW X X her zaman bir gerçeğe uygun değer üretecek

SUGGEST X Y- Eğer X ve Y'nin arkadaş olması gerekiyorsa, aksi taktirde sahte bir değer verin. X ve Y şu durumlarda arkadaş olmalıdır:

  • X ve Y arkadaş değil

  • X ve Y'nin en az 1 arkadaşı var

Sen değiştirmek için izin verilir FRIEND, SUGGESTve KNOWkendi dizeler, ama sen her komutu yerini ne dize belirtmek zorundadır.

Programınız, nasıl çalıştığını anlamak oldukça kolay olduğu sürece, istediğiniz şekilde girdi / üretim çıktısı alabilir.

Sosyal ağdaki insan sayısı N1 ile 100,000 arasındadır, ancak herhangi bir sayıda "arkadaş bağı" (kenarlar) olabilir.

Henüz farketmediyseniz, bu grafik arama sorunudur. Bunu uygulamak için (muhtemel) en kolay (ve muhtemelen en hızlı) veri yapısı bir bitişiklik matrisi olacaktır.

Test durumları

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

Resim formunda bazı test örnekleri

Koşulu kazanmak

Bu , en kısa kod kazanır!


Örneğin, ağdaki tüm insanların bir listesini girerek başlayabilir miyiz {A, B, C, D}?
Greg Martin

2
Test durumlarının metin halinde olması çok daha yararlı olacaktır.
Greg Martin

1
FRIEND komutundan sonra çıktı alabilir miyiz?
ovs

7
SUGGEST UK EU.
WBT

1
@Thunda, Python'da yerleşik REPL'in kullanılması komutta iki ekstra karakter gerektirir. Bunun gibi diller, bu ekstra baytları programın toplam uzunluğuna eklemeli midir?
quintopia

Yanıtlar:


44

SWI-Prolog, 62 47 41 bayt

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

Prolog çok sık işe yaramaz, ancak güzel olduğunda. Biz kullanacağız a+bnotate aarkadaş olduğunu b, a*bo abilir bve a?bo bönerdi edilmelidir aya da değil. İlk satır sadece diyor X*Yya bu durum geçerlidir X+Y, Y+Xya da X == Ydoğrudur. Bu, birbirlerini tanımanın simetrisini uygular. Bir öneri olup olmadığını sormak son derece basittir. Sadece bir olup olmadığını sormak Zböyle X*Ysahte ve X*Zve Y*Zdoğrudur. Tam olarak mücadelede tanımlandığı gibi.

Bunu bir dosya olarak kaydederseniz (örn. friends.pl) Ve SWI-Prolog'u bu dosyayla ( prolog -l friends.pl) açarsanız, bir REPL'e bırakılırsınız.

Böyle arkadaşlıklar söyleyebilirsin:

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

İnsanların birbirlerini bildiğini veya önerilip önerilmediğini kontrol edebilirsiniz:

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

Sen yerine bayt, bir avuç gerekir k(X,Y)ile X*Yve aynı fve sfarklı işlenen kullanarak. Doğru saydıysam 21 byte.
Emigna

Yine de iddialarla nasıl çalıştıklarından emin değilim, bu yüzden emin değilim f.
Emigna

12
Sorunun bir kısmını tasarlayan veri yapısı boyunca tamamen osurur. Şaşırtıcı.
Thunda

@Emigna Uyguladım, ama saydığın kadar tasarruf etmedi.
orlp

Ben gibi test bu 41 bayt. Yine de denemek için bir REPL yok, bu yüzden orada farklı çalışıp çalışmadığını bilmiyorum.
Emigna

15

PHP, 138 133 129 bayt

PHP Mathematica'yı yener - nadir görülen bir durum.

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

1gerçeği için baskı , sahte için boş dize. Çevrimiçi olarak çalıştırın -nrveya test edin .
Liste ataması için PHP 7.1'e ihtiyacı var; kullanıcı adları küçük harfe duyarlıdır ve dışlamak gerektiğini a, b, s.

Yıkmak

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 newline karakterini içerdiğinden kırpılmalıdır.
  • array_intersect_keysessiz olması gerekir ya da boş için uyarıları doğuracak $$aveya $$b.
  • 18 tüm kullanıcı adları için 15 bayt: Değiştir $$aile $f[$a]ve $$bile $f[$b].

12

CMD (Toplu), 50 + 20 + 135 = 205 bayt

  • FRIEND.CMD

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

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

    1Arkadaşlarınız için yazdırır , yabancılar için boş bir satır.

  • SUGGEST.CMD

    @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%
    

    Yazdırır 1veya boş bir satır. Bence üst üste altı %saniye, yeni bir kişisel en iyi olabilir.


Bu delice harika. Güzel çözüm.
AdmBorkBork

6

Python 3, 122 118 + 2 = 120 bayt

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)

Kullanım tam olarak ovs'un cevabı ile aynı.


1
Benim için oldukça açık, ancak gereksinimler REPL'inizi ve hangi komutlarla kullanacağınızı belirtmeniz gerektiğini söylüyor. Python bilmeyenler için faydalı olabilir. (Bu arada, bu benim tam olarak kullanacağım yöntem.)
quintopia

6

Python 3, 163 149 143 + 2 = 145 bayt

@FelipeNardiBatista sayesinde -6 bayt

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}

Bunun kaydet bir dosyaya ve olarak çalıştırın python3 -i file.py
Kullanım
- f("a", "b")yerine FRIENDS a b
- k("a", "b")yerine KNOW a b
- s("a", "b")yerineSUGGEST a b

Falsey çıkışı: 0, set (), Yanlış
Truthy çıkışı: boş olmayan set, Doğru

Çevrimiçi deneyin


Python yorumlayıcısı REPL olarak kullanılmadığında 164 bayt:

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

Kullanımları
- fiçin FRIEND
- siçin SUGGEST
- için başka bir şeyKNOW

Çevrimiçi deneyin


İkinci bağlantı için
öneri

@Thunda düzelttim
ovs

Bir şeyi kaçırıyorsam düzeltin, ama bunun yerine, l.extend([(a,b),(b,a)])yapamaz l+=[(a,b),(b,a)]mısınız? (Bunu henüz test etmedim)
HyperNeutrino

Ah üzgünüm, benim hatamın farkına vardım, bu bir UnboundLocalError. Bu arada güzel cevap!
HyperNeutrino

Eğer kaldırırsanız bool()gelen sişlevi ve kullanım 0, {}ve Falseve Falsey olarak Trueve boş değil setTruthy gibi, sen 6 bayt kurtarabilecek
Felipe Nardi Batista

5

Mathematica, 164 bayt

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@##&

Üç ana işlevleri tanımlar F, Sve Kistenen davranışı ile. Örneğin, komutların sırası

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’ye bağlı görüntüden alınan son test durumudur; Fkomutlar, hiçbir çıkış (tek noktalı virgül bunun için ödeme için küçük bir fiyat görünüyor) verim altı iken Sve Kkomutlar verim

True
True
False
False
True
True

istediğiniz gibi.

Herhangi bir anda, fformun sipariş çiftlerinin listesi bilir iken, bazı unsuru görünen kişilerin listesidir . Arayan dört sıralı çiftleri ekler , , , ve için .{A, B}ABpfF@{A, B}{A, B}{B, A}{A, A}{B, B}f

Ayrıca, herhangi bir anda, malttaki grafiğin bitişik matrisidir (bir kişi kendilerine ve tüm kullanıcılarına Fbitişiktir); satırlar ve sütunlar tarafından indekslenir pve ibir kişiyi karşılık gelen satır / sütun numarasına dönüştürür. Yardımcı fonksiyon abir matris alır ve iki kişi giriş olarak bakar ve "koordinatları" iki olan matrisin girişine bakar True, sayı pozitif ise ve Falsesıfır ise döner . (Ayrıca a, giriş yapan kişilerden biri henüz tanınmadığında da arama yapmak mümkündür - örneğin, herhangi bir ARKADAŞ bildirimlerinden önce bir KNOW veya ÖNERİ sorgusu yapmak veya arkadaşı olmayan bazı fakir bir insan hakkında soru sormak; /._@__->0çıktıyı Falseyine de olmaya zorlar .)

K[A, B]Bu nedenle, çağrı m[A, B], olumlu olup olmadığını araştırır ; bu, Kşimdi fiili uygular . Matris ürünü m.m, uzunluk 2 yolu boyunca bir kişiden diğerine geçme yollarının sayısını içeren uzunluk-2 yollu matristir; Bu, ek olarak fiili S[A, B]uygulayabilmenizi sağlar S, ek olarak elle &&!K@##girilen kişilerin birbirlerini tanımadıklarını kontrol ettikçe ( ).

Eğlenceli bir gerçek: ücretsiz bu uygulama, bize ait klikler beyan olanak arkadaşlar-komuta F@{A, B, C, D}tüm eşdeğerdir F@{A, B}, F@{A, C}, F@{A, D}, F@{B, C}, F@{B, D}, ve F@{C, D}birleştirdi.


2

Python 2 , 118 bayt

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

Çevrimiçi deneyin!

Python 2 için repl çevrimiçi aracını bulamadığımdan, TIO Nexus'u (REPL formatında) ekledim.

Seçenek ve olası çıktı için sorgu

0 - Bilinen - Yok

1 Arkadaş için - Doğru veya Yanlış

2 için Öner - Doğru veya Yanlış

Repl python yorumlayıcısında kullanım örneği ve örnek çıktı.

>>> 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 bayrakları) = 160 bayt

Sed, regex tabanlı bir dil olduğundan soyut veri yapılarından bahsetmek yerine ilkel türler yoktur. Ağ verisi, serbest biçimli metin olarak saklanır, bu durumda A-B;B-A;, daha sonra çeşitli regex düzenleriyle eşleştirilen gereksiz arkadaş bağlantıları vb.

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

Çevrimiçi deneyin!

Tasarım gereği sed, her giriş satırı için tüm betiği çalıştırır. Yazmadan hemen sonra komutun çıktısını görmek için etkileşimli modda test etmenizi öneririm.

Kullanımı: sed'de hiçbir truthy / falsy değeri yoktur, bu yüzden kullandığım çıktı sözleşmesi bash'tan ödünç alınır, burada boş olmayan bir dize truthy olarak kabul edilir ve boş bir string sahte olarak kabul edilir.

  • F X Yiçin FRIEND X Y. Çıkışı yok.
  • K X Yiçin KNOW X Y. 'K' yi truthy, hiçbir şeyi sahte değildir.
  • S X Yiçin SUGGEST X Y. 'S' yi truthy ve hiçbir şey sahte değil.

Açıklama:

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'.
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.