Çok fazla casus!


38

Geniş bir düşman casusları ağıyla savaşıyorsunuz . Her casusun kullanmayı sevdikleri en az bir (bazen çoklu) sahte kimliğe sahip olduğunu biliyorsunuz . Gerçekten kaç tane casusla uğraştığını bilmek istiyorsun.

Neyse ki, karşı istihbarat ajanlarınız işlerini yapıyor ve bazen iki sahte kimliğin aslında aynı düşman casusu tarafından kontrol edildiğini anlayabilir.

Demek ki:

  • Ajanlarınız her zaman iki sahte kimliğin arkasında aynı casusu olduğunu bilmiyor.
  • Bir ajan size iki sahte kimliğin aynı casus tarafından kontrol edildiğini söylerse, haklı olduklarına güvenirsiniz.

Ajan mesajları

Ajanlar size hangi kimliklerin aynı casuslara sahip olduklarını söyleyen şifreli mesajlar gönderir. Bir örnek:

You have 2 ajanları ve 5 sahte kimlikler ile başa çıkmak için.

İlk ajan size bir mesaj gönderir:

Red Red Blue Orange Orange

Bu, 3 casus olduğunu düşünüyorlar:

  • ilki (Kırmızı) 1 ve 2 kimliklerini kontrol eder.
  • ikincisi (Mavi) kimliği kontrol eder 3
  • Üçüncüsü (Turuncu) 4 ve 5 kimliklerini kontrol eder.

İkinci ajan size bir mesaj gönderir:

cat dog dog bird fly

Bu 4 casus olduğunu düşünüyorlar:

  • ilki (kedi) kimliği kontrol eder 1
  • ikincisi (köpek) 2 ve 3 numaralı kimlikleri kontrol eder.
  • üçüncüsü (kuş) kimliği kontrol eder 4
  • dördüncü olan (sinek) kimliği kontrol eder 5

Gördüğümüz bilgileri derlerken:

Identities:   id1    id2    id3    id4    id5 
Agent 1:    |--same-spy--|       |--same-spy--|
Agent 2:           |--same-spy--|
Conclusion: |-----same-spy------||--same-spy--|

Bu, en fazla 2 casus olduğu anlamına gelir .

notlar

Aynı casusun sahip olduğu kimliklerin ardışık olması gerekmez, örneğin:

dog cat dog

geçerlidir

Ayrıca, aynı kelime iki farklı ajan tarafından da kullanılabilir - bu bir anlam ifade etmiyor, sadece bir tesadüf, örneğin:

Agent 1: Steam Water Ice
Agent 2: Ice Ice Baby

Buz, her iki ajan tarafından da kullanılır - Icebirinci ajan Icetarafından kullanılan, ikinci ajan tarafından kullanılan iki olay ile ilişkili değildir .

Meydan okuma

Tüm ajanlarının istihbaratını topla ve kaç düşman casusu olduğunu bul. (Daha kesin olmak için, sahip olduğunuz sınırlı bilgi göz önüne alındığında, en düşük üst sınırı alın.)

Bayt cinsinden en kısa kod kazanır.

Giriş ve Çıkış özellikleri

Giriş, aracılardan n mesajlarını temsil eden n satırlarının bir listesidir. Her satır, k ile boşluk bırakılmış belirteçlerden oluşur, tüm satırlar için aynı k. Jetonlar alfasayısal, isteğe bağlı uzunluktadır. Dava önemli.

Çıktı, acentalarınızın bilgisine dayanarak, farklı casusların sayısını temsil eden tek bir sayı olmalıdır.

Örnekler

örnek 1

Giriş:

Angel Devil Angel Joker Thief Thief
Ra Ra Ras Pu Ti N
say sea c c see cee

Çıktı:

2

Örnek 2

Giriş:

Blossom Bubbles Buttercup
Ed Edd Eddy

Çıktı:

3

Örnek 3

Giriş:

Botswana Botswana Botswana
Left Middle Right

Çıktı:

1

Örnek 4

Giriş:

Black White
White Black

Çıktı:

2

Örnek 5

Giriş:

Foo Bar Foo
Foo Bar Bar

Çıktı:

1

Örnek 6

Giriş:

A B C D
A A C D
A B C C
A B B D

Çıktı:

1

Örnek 7

Giriş:

A B A C

Çıktı:

3

Örnek 8

Giriş:

A
B
C

Çıktı:

1

Örnek 9

Giriş:

X

Çıktı:

1

Her satırı bir kelime dizisi olarak alabilir miyiz?
Arnauld,

8
@HenryHenrinson Girdiyi katı yapan tek şey, giriş biçimini değiştirmek için kodun başlangıcına kısa bir bulanıklık eklenmesidir. Gerçekten meydan okumaya bir şey
eklemiyor

6
Bana öyle geliyor gibi kod golf
oynamak

17
Sıkı I / O formatları, mücadelenin özünden uzaklaştığı için kesinlikle önerilmez. Örneğin, girişin boşlukla ayrılmış kelimelerin satırları şeklinde yapılmasını zorunlu kılmanıza gerek yoktur, çünkü biri her bir satırı bir sözcük listesi (Arnauld'un söylediği) ve bu kuralın mücadeleye kattığı tek şey olarak da gösterebilir. çizgileri bölme zorunluluğu, mutlaka mücadelenin bir parçası olmayan bir şey.
Outgolfer Erik,

2
Bu başlık, ortalama Team Fortress 2 oyununa benziyor!
Tvde1

Yanıtlar:


10

Balyoz 0.5.1 , 16 15 bayt

⡡⠥⡀⡾⠥⢢⠍⣽⡷⣩⣅⡷⣡⢒⠅

Bu Wolfram Dili fonksiyonuna sıkıştırır (final geçerlidir &):

Length[ConnectedComponents[RelationGraph[Inner[Equal, ##1, Or] &,
    Transpose[StringSplit @ #1]]]] &

Çevrimiçi deneyin!

Transpose[StringSplit @ #1]: Giriş listesindeki her dizgiyi böler ve sütunları alır (casus kimlikleri)

RelationGraph[Inner[Equal, ##1, Or] &, ...]: En az bir pozisyon eşitse iki köşenin bir kenarı paylaştığı grafiği oluşturun (eğer bir dost ajan tarafından aynı casus olarak sınıflandırılmışlarsa)

Length[ConnectedComponents[...]]: Bağlı bileşenlerin sayısı, olası casus sayısına bağlı olarak üst sınırdır.


9

JavaScript (Node.js) ,  155 150 142  141 bayt

a=>new Set((a=a.map(s=>s.split` `))[0].map((_,x)=>a.flat(m=1<<x).map(o=_=>a.map((b,y)=>b.map((w,i)=>m>>i&1|o[w+=y]?o[w]=m|=1<<i:0)))|m)).size

Çevrimiçi deneyin!

Nasıl?

xmx

+---------+-------+-------+-------+-------+-------+-------+
| x       |   0   |   1   |   2   |   3   |   4   |   5   |
+---------+-------+-------+-------+-------+-------+-------+
| 2**x    |   1   |   2   |   4   |   8   |  16   |  32   |
+---------+-------+-------+-------+-------+-------+-------+
| words   | Angel | Devil | Angel | Joker | Thief | Thief |
|         | Ra    | Ra    | Ras   | Pu    | Ti    | N     |
|         | say   | sea   | c     | c     | see   | cee   |
+---------+-------+-------+-------+-------+-------+-------+
| bitmask |  15   |  15   |  15   |  15   |  48   |  48   |
+---------+-------+-------+-------+-------+-------+-------+

Yorumlananlar

a =>                      // a[] = input
new Set(                  // we eventually convert the generated array into a set
  (a = a.map(s =>         // we first need to convert each line into
    s.split` `            // an array of words (*sigh*)
  ))                      //
  [0].map((_, x) =>       // for each word at position x in the first line:
    a.flat(m = 1 << x)    //   initialize a bitmask m with the x-th bit set and build an
                          //   array containing as many entries (N) as there are words in
                          //   the whole matrix
    .map(o =              //   the object o is used to store words
         _ =>             //   repeat N times to ensure that all relations are found:
      a.map((b, y) =>     //     for each line b[] at position y in a[]:
        b.map((w, i) =>   //       for each word w at position i in b[]:
          m >> i & 1 |    //         if the i-th bit is set in m (the relation already
                          //         exists)
          o[w += y] ?     //         or w + y is set in o (a relation exists in this line):
            o[w] =        //           set o[w + y] (the value doesn't matter as long as
                          //           it's non-zero)
              m |= 1 << i //           set the i-th bit in m
          :               //         else:
            0             //           do nothing
        )                 //       end of map() over the words
      )                   //     end of map() over the lines
    ) | m                 //   end of map() over all flatten entries; yield m
  )                       // end of map() over x
).size                    // return the size of the corresponding set

Yani ... pratikte bunun 32 ya da 64 kimlik limiti olur mu?
Vilx

@ Vilx- Bence elbette Bayt'a mal olsa da, BigInt'a geçebileceğini düşünüyorum.
Neil,

6

Jöle , 19 bayt

ḲiⱮ`)ZŒc€ẎyⱮ@ƒƊÐLQL

Çevrimiçi deneyin!

Girdiyi boşlukla ayrılmış satırların listesi olarak alır (altbilgi buna karşılık gelir).

Not: ḲŒQ)PSyok değil çalışır.


6

Python 3 , 132 162 154 139 135 bayt

def f(a):r=[*zip(*[map(b.index,b)for b in map(str.split,a)])];return sum(i==min(min(u)for u in r if min(w)in u)for i,w in enumerate(r))

Çevrimiçi deneyin!

Bu, kümeleri tanımlayan bir grafik algoritmasının çok kompakt bir uygulamasıdır.

  1. Her ajan için, görünüm en düşük endeksidir profilleri ve onların takma bir harita oluşturmak: [map(b.index,b)for b in map(str.split,a)]. Yani [0,1,2,1,2], ilk profilin bir, ikinci ve dördüncü, diğerinin üçüncü ve beşinci olduğu üç casusu tanımlamaktadır. Grup endeksi aynı zamanda gruptaki ilk profilin endeksidir.

  2. Bu matrisi ( [*zip(*m...)]) transpoze ederek, her profil için bir grup üyeliği elde ediyoruz. Bu, yönlendirilmiş, asiklik bir grafik oluşturur, çünkü grup endeksleri profil endekslerinin bir alt kümesidir ve tüm kenarlar düşük veya eşit endekslere doğru ilerler. Aynı casusa karşılık gelen profiller artık diğer profillere bağlantısı olmayan bir küme oluşturmaktadır. Yine de yinelenen yollarımız var, çünkü profil endeksleri birden fazla grup endeksine bağlı.

  3. Aşağıdaki döngülerle grafiği, tüm profillerin doğrudan ağaçlarındaki en düşük endekse, yani köke bağlandığı düz bir ormana indiririz: min(min(u)for u in r if min(w)in u)

  4. Son olarak, ormandaki kökleri sayısını döndürmek, kendilerine bağlı yani endeksleri: return sum(i==...).


Girinti gerekli mi? Python kullandığımdan beri çok uzun zaman geçti ama oneliner yapabileceğini hatırlıyor gibiyim.
Mark Gardner

Yapabilirsin ama iç içe geçmiş döngüler kullanıyorsan kullanamazsın. Kendiniz için TIO;)
movatica

5

Kömür , 49 43 bayt

≔⪪S θWS«≔⪪ι ιFLιUMθ⎇⁼λ§θκ§θ⌕ι§ικλ»ILΦθ⁼κ⌕θι

Çevrimiçi deneyin! Bağlantı, kodun ayrıntılı bir versiyonudur. Hantal bir giriş formatı kullanarak birkaç byte tasarruf mümkün olabilir. Açıklama:

≔⪪S θ

İlk ajanın listesini girin.

WS«

Kalan ajanlar için tekrarlayın.

≔⪪ι ι

Onların listesini girin.

FLι

Her bir öğe endeksinin üzerinden döngü.

UMθ⎇⁼λ§θκ§θ⌕ι§ικλ»

Bu aracının listesindeki ilk öğeyi aynı kimliğe sahip bulun ve aynı aracın kimliğini göstermek için ilk aracının listesini güncelleyin.

ILΦθ⁼κ⌕θι

Kalan benzersiz kimlik sayısını sayın.


5

Jöle , 25 15 bayt

ḲĠ)ẎfƇFQɗⱮQ$ÐLL

Çevrimiçi deneyin!

Boşluk-ayırıcı ajan taleplerinin bir listesini alan ve farklı casusların sayısının en düşük üst sınırını getiren bir monadik bağlantı.

açıklama

  )              | For each list:
Ḳ                | - Split at spaces
 Ġ               | - Group indices of equal items
   Ẏ             | Tighten lists, so we have a single list of grouped indices
           $ÐL   | Repeat the following until no change:
        ʋⱮQ      | - Do the following as a dyad, mapping through each element of the uniquified list as the right argument
    fƇ           |   - Keep only those list members with one or more items matching the right argument
      F          |   - Flatten
       Q         |   - Uniquify
              L  | Finally take the length of the resultant list

Önceki sürümlerle ilgili sorunları belirlemek için @Arnauld ve @JonathanAllan'a ve bir bayt tasarrufu için tekrar @JonathanAllan'a teşekkürler! Giriş belirtimi listelerin bir listesine izin vermek için gevşetilseydi, bu bir bayttan tasarruf sağlar.


Ben düşünüyorum sıralama aslında gereksiz olabilir gelen gruplar halinde endeksleri beri Ġfiltre sonucu kopyalanmamış, sıralanabilir ve düzleşir, fƇFQher zaman, tekrarlanan uygulamadan sonra, örneğin (sıralı düzende bunlarla sona ereceğini 'a a b b c', 'a b a b cnihai bir bulamazsınız [3,4,1,2], yol boyunca görünmesine rağmen). Yani ḲĠ)ẎfƇFQɗⱮQ$ÐLL15 için iyi olabilir?
Jonathan Allan,

@ JonathanAllan iyi nokta. Biraz oyun oynadım (ve nasıl çalıştığını düşünüyorum) ve haklı olduğunuzu düşünüyorum.
Nick Kennedy,

4

JavaScript (Node.js) , 120 bayt

a=>a.map(l=>(s=l.split` `).map((w,i)=>r[o(i)]=o(s.indexOf(w)),o=i=>r[i]-i?o(r[i]):i),r=[])|r.map(g=(v,i)=>t+=v==i,t=0)|t

Çevrimiçi deneyin!

a=>a.map(l=>(                  // for each line
  (s=l.split` `).map((w,i)=>(  // for each words in line
    r[o(i)]=o(s.indexOf(w)),   // join(current index, first occurrence index)
  )),                          //   without updating nodes in path
  o=i=>r[i]-i?o(r[i]):i,       // a function to find root of some node
  r=[]                         // initial disjoint-set
))|
r.map(g=(v,i)=>t+=v==i,t=0)|   // count roots of tree
t                              // output

3

Kabuğu , 12 bayt

LωomΣknṁoηkw

Çevrimiçi deneyin!

açıklama

Buradaki fikir, aynı kişi olduğu bilinen tüm casus gruplarının bir listesini oluşturmak ve ardından kesişen grupları sabit bir noktaya ulaşana kadar aşamalı olarak birleştirmektir. Çıktı birleştirilemeyen kalan grupların sayısıdır.

LωomΣknṁoηkw  Implicit input: list of strings, say ["a bc a","b g g"]
       ṁ      Map and concatenate:
           w   Split at spaces: "a bc a" becomes ["a","bc","a"]
         ηk    Group indices by equality of elements: [[1,3],[2]]
              Result: [[1,3],[2],[1],[2,3]]
 ω            Iterate until result doesn't change:
     k         Group greedily by
      n        (non-emptiness of) intersection: [[[1,3],[1]],[[2],[2,3]]]
   mΣ          Concatenate each part: [[1,3,1],[2,2,3]]
              Result: [[1,3,1,2,2,3]]
L             Length: 1


3

Ruby , 123 117 bayt

Movatica'nın Python 3 çözümüne benzer bir fikir kullanır, ancak her "ağaç" için en düşük casus endeksini biraz farklı bir şekilde hesaplar (önceki karşılaşılan profilleri izleyerek , varsa bir üst üste binme bularak ve bunları birleştirerek)

@GB'tan -6 bayt.

->a,*b{a.map{|s|e=s.split;e.map{|i|e.index i}}.transpose.map{|e|b<<(b.find{|i|i-e!=i}||[])+e}
b.map(&:min).uniq.size}

Çevrimiçi deneyin!

açıklama

->a,*b{                                             # Start lambda with input a, b=[]
       x=
         a.map{|s|                             }    # For each agent's report
                  e=s.split;                        # Split the words
                            e.map{|i|e.index i}     # Get spy number for each

   .transpose                                       # Transpose to get group membership
             .map{|e|                            }  # For each profile
                        (b.find{|i|i-e!=i}||[])     # Find a profile in b that overlaps
                                                    #  If one is not found, use []
                                               +e   # Add the profile onto the found one
                     b<<                            # Insert this modified profile into b

b.map(&:min)                                        # Get minimum of each modded profile
            .uniq                                   # Deduplicate
                 .size                              # Size of array
}                                                   # Implicit return

Patlama ve sıkıştırma yerine, sadece transpoze edebilirsiniz.
GB


@GB başkanları için teşekkürler; Sonsuza kadar dizileri devretmek için pop-zip veya shift-zip kullanıyorum! Ayrıca, kullanma hileniz s.split.map{|i|s.index i}hoş, ancak girişlerin uzunluğuna bağlı olarak kenar durumları oluşturabilir. Bu giriş 2 değil 3 döndürmelidir.
Value Ink 16

2

Python 2 , 229 221 bayt

e=enumerate
def f(s):
 v=[];u=sum([(lambda a:[{i for i,x in e(a)if x==k}for k in set(a)])(a.split())for a in s.split('\n')],v)
 while u:
	x=u.pop()
	for i,y in e(u):
	 if x&y:u.pop(i);u+=[x|y];break
	else:v+=[x]
 return v

Çevrimiçi deneyin!

Wilkben'e 8 bayt thx .


Yana gsadece bir kez kullanılır, satır içi tanımlamak olamazdı? Python'da mümkün olup olmadığını unutmuşum ama hatırlıyorum gibi görünüyor.
Stephen


1

137 bayt temiz

import StdEnv,Text,Data.List
q=length
$l=q(iter(q l)(map flatten o groupBy isAnyMember)(transpose[[(s,n)\\s<-split" "z]\\z<-l&n<-[1..]]))

Çevrimiçi deneyin!

Temsilciler tarafından kullanılan ipleri, temsilciler arasında eşitliği önlemek için görünen satır numarası ile ilişkilendirir, ardından herhangi bir konum için herhangi bir ifadenin üst üste gelip gelmediğini kontrol eder ve elde edilen setlerin sayısını sayar.


0

PHP , 271 bayt

Kimliklerden herhangi biri sadece "casus numarasını" kimlikleriyle birlikte sakladığım gibi sayılarsa işe yaramaz. Yine de bunu düzeltmenin zor olmayacağını sanmıyorum.

$a=$argv;array_shift($a);if(count($a)==1)array_push($a,...$a);foreach($a as&$b)$b=explode(" ",$b);$c=array_map(null,...$a);foreach($c as&$d)foreach($d as$k=>$e){if(!$d[s])$d[s]=++$s;foreach($c as&$f)if($f[$k]==$e)$f[s]=$d[s];}echo count(array_unique(array_column($c,s)));

Çevrimiçi deneyin!

açıklama

Bunu yazarken kafam karıştı, ama tüm test durumlarında işe yarıyor!

$a=$argv;					//shorten the arguments variable
array_shift($a);				//removes the script name from the arguments variable
if(count($a)==1)array_push($a,...$a);		//the code needs at least 2 messages to run so if only 1 message duplicate it. "..." passes the stuff in the array rather than the array itself?
foreach($a as&$b)$b=explode(" ",$b);		//turns each string message into an array
$c=array_map(null,...$a);			//if you give array_map "null" for the callabck then it zips the arrays, turning a m by n 2D array into a n by m 2D array. this changes it from the messages being grouped to the identities being grouped
foreach($c as&$d)				//loop over the groups of identities
	foreach($d as$k=>$e)			//loop over the names the agents gave the identity and keep track of the key
	{
		if(!$d[s])$d[s]=++$s;		//if this identity doesn't have a "spy number" give it the next one
		foreach($c as&$f)		//loop over the groups of identities again
			if($f[$k]==$e)		//check if the agents gave any other identities this name 
				$f[s]=$d[s];	//if they did then give those the same "spy number"
	}
echo count(array_unique(array_column($c,s)));	//use array_column to get the "spy number" of each identity, remove duplicates using array_unique and then count the size of the array giving the upper limit of spies

Çevrimiçi deneyin!

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.