스파이가 너무 많습니다!


38

당신은 광범위한 적 스파이 네트워크를 싸우고 있습니다. 각 스파이에는 사용하기를 원하는 하나 이상의 가짜 신원이 있을 수 있습니다. 당신은 실제로 얼마나 많은 스파이를 상대하고 있는지 알고 싶습니다.

운 좋게도, 당신의 반 지능 요원 들이 그들의 일을하고 있고 때로는 두 명의 가짜 신원이 실제로 같은 적 스파이에 의해 통제되는 시점을 알아낼 수 있습니다 .

즉 말하자면:

  • 에이전트는 두 명의 가짜 신원이 그들 뒤에 동일한 스파이를 가지고 있는지 항상 알지 못합니다.
  • 에이전트가 두 명의 가짜 신원이 동일한 스파이에 의해 제어된다고 말하면 그들이 옳다는 것을 믿습니다.

에이전트 메시지

에이전트는 비밀 메시지를 보내 어떤 스파이어와 동일한 스파이를 가지고 있는지 알려줍니다. 예를 들면 :

당신은 이 에이전트5 명 가짜 신원 을 처리 할 수 있습니다.

첫 번째 상담원이 메시지를 보냅니다.

Red Red Blue Orange Orange

이것은 그들이 3 명의 스파이가 있다고 생각한다는 것을 의미합니다 :

  • 첫 번째 (빨간색)는 ID 1과 2를 제어합니다.
  • 두 번째 (파란색)는 ID 3을 제어합니다.
  • 세 번째 (주황색)는 ID 4와 5를 제어합니다.

두 번째 에이전트는 다음과 같은 메시지를 보냅니다.

cat dog dog bird fly

즉, 그들은 4 명의 스파이가 있다고 생각합니다.

  • 첫 번째 (고양이)는 정체성을 제어 1
  • 두 번째 (개)는 신원 2와 3을 통제합니다
  • 세 번째 (조류)는 정체성을 통제한다 4
  • 네 번째 (비행)는 정체성 5를 통제한다

인텔을 컴파일하면 다음과 같습니다.

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

이것은 최대 2 명의 스파이 가 있음을 의미 합니다.

노트

동일한 스파이가 소유 한 ID는 연속적 일 필요는 없습니다.

dog cat dog

유효합니다.

또한 동일한 단어가 두 개의 다른 에이전트에 의해 사용될 수 있습니다. 즉, 아무 의미도 없으며, 우연의 일치입니다.

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

얼음은 두 요원이 Ice사용합니다. 첫 번째 요원이 Ice사용한 것은 두 번째 요원 이 사용한 두 가지 발생과 관련이 없습니다 .

도전

모든 요원의 정보를 수집하고 얼마나 많은 적 스파이가 있는지 알아 내십시오. (정확한 정보를 얻으려면 가장 정확한 상한을 얻으십시오.)

바이트 단위의 가장 짧은 코드가 이깁니다.

입력 및 출력 사양

입력은 에이전트의 n 메시지를 나타내는 n 줄의 목록입니다. 각 줄은 공백으로 구분 된 k 개의 토큰으로 구성되며 모든 줄에 대해 같은 k입니다. 토큰은 영숫자, 임의 길이입니다. 사건이 중요합니다.

출력은 에이전트의 인텔을 기준으로 고유 한 스파이 수를 나타내는 단일 숫자 여야합니다.

실시 예 1

입력:

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

산출:

2

실시 예 2

입력:

Blossom Bubbles Buttercup
Ed Edd Eddy

산출:

3

실시 예 3

입력:

Botswana Botswana Botswana
Left Middle Right

산출:

1

실시 예 4

입력:

Black White
White Black

산출:

2

실시 예 5

입력:

Foo Bar Foo
Foo Bar Bar

산출:

1

실시 예 6

입력:

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

산출:

1

실시 예 7

입력:

A B A C

산출:

3

실시 예 8

입력:

A
B
C

산출:

1

실시 예 9

입력:

X

산출:

1

각 줄을 단어의 배열로 볼 수 있습니까?
Arnauld

8
@HenryHenrinson 입력을 엄격하게하는 것은 코드 시작 부분에 짧은 흐림을 추가하여 입력 형식을 변경하는 것입니다. 그것은 도전 자체에 아무 것도 추가하지 않습니다
fəˈnɛtɪk

6
그런 소리가
들리면

17
엄격한 I / O 형식은 문제의 핵심에서 벗어나기 때문에 권장하지 않습니다. 예를 들어, 입력을 공백으로 구분 된 단어의 줄 형태로 시행 할 필요는 없습니다. 각 줄을 단어 목록 (Arnauld가 말한 것)으로 나타낼 수도 있고이 규칙이 도전에 추가하는 유일한 것이므로 라인을 분할해야 할 필요성이 있습니다. 반드시 도전의 일부는 아닙니다.
Outgolfer Erik

2
이 타이틀은 일반적인 Team Fortress 2 게임처럼 들립니다!
Tvde1

답변:


10

슬레지 해머 0.5.1 , 16 15 바이트

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

이 Wolfram Language 기능으로 압축을 풉니 다 (최종 &은 내재적 임).

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

온라인으로 사용해보십시오!

Transpose[StringSplit @ #1]: 입력 목록에서 각 문자열을 분할하고 열 (스파이 ID)을 가져옵니다.

RelationGraph[Inner[Equal, ##1, Or] &, ...]: 하나 이상의 위치가 같은 경우 두 정점이 모서리를 공유하는 그래프를 구성합니다 (일부 친근한 에이전트에 의해 동일한 스파이로 분류 된 경우).

Length[ConnectedComponents[...]]: 연결된 구성 요소의 수는 가능한 스파이 수의 상한입니다.


9

자바 스크립트 (Node.js를) ,  155 (150) 142  141 바이트

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

온라인으로 사용해보십시오!

어떻게?

각 열 에 대해 링크 열 ( 번째 열 포함)의 비트 마스크 을 만듭니다. 결국 고유 한 비트 마스크 수를 반환합니다.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   |
+---------+-------+-------+-------+-------+-------+-------+

댓글

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

실제로 ... 실제로 32 또는 64 개의 ID 제한이 있습니까?
Vilx-

@ Vilx- 물론 바이트 비용이 들지만 BigInt로 전환 할 수 있다고 생각합니다.


6

파이썬 (3) , 132 (162) 154 (139) 135 바이트

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

온라인으로 사용해보십시오!

이것은 클러스터를 식별하는 그래프 알고리즘의 매우 컴팩트 한 구현입니다.

  1. 각 에이전트에 대해 프로파일 및 해당 별명 맵을 작성합니다. 이는 가장 낮은 모양 색인입니다 [map(b.index,b)for b in map(str.split,a)]. 즉 [0,1,2,1,2], 첫 번째 프로필은 하나, 두 번째 및 네 번째는 다른 하나에 속하고 세 번째 및 다섯 번째는 마지막 하나에 속하는 세 명의 스파이를 식별합니다. 그룹 색인은 그룹에서 첫 번째 프로파일의 색인이기도합니다.

  2. 이 행렬 ( [*zip(*m...)]) 을 바꿈 으로써 각 프로파일에 대한 그룹 멤버십을 얻습니다. 그룹 인덱스는 프로파일 인덱스의 하위 집합이며 모든 모서리가 더 낮거나 같은 인덱스를 향하기 때문에 이것은 방향이 지정된 비순환 그래프를 형성합니다. 동일한 스파이에 해당하는 프로필이 이제 다른 프로필에 연결되지 않은 클러스터를 형성합니다. 프로파일 인덱스는 여러 그룹 인덱스에 연결되어 있기 때문에 여전히 중복 경로가 있습니다.

  3. 다음 루프를 사용하면 그래프가 플랫 포리스트로 최소화되어 모든 프로필이 트리의 가장 낮은 인덱스 (예 : 루트)에 직접 연결됩니다. min(min(u)for u in r if min(w)in u)

  4. 마지막으로, 숲에있는 뿌리의 수, 즉 그들 자신에게 연결된 인덱스를 반환하십시오 : return sum(i==...).


들여 쓰기가 필요합니까? 파이썬을 사용한 지 오래되지 않았지만 원 라이너를 만들 수 있다는 것을 기억합니다.
마크 가드너

중첩 된 for 루프를 사용하는 경우 가능하지만 할 수는 없습니다. 자신을위한 TIO;)
movatica

5

, 49 43 바이트

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

온라인으로 사용해보십시오! 링크는 자세한 버전의 코드입니다. 번거로운 입력 형식을 사용하여 몇 바이트를 저장할 수 있습니다. 설명:

≔⪪S θ

첫 번째 상담원 목록을 입력하십시오.

WS«

나머지 에이전트에 대해 반복하십시오.

≔⪪ι ι

그들의 목록을 입력하십시오.

FLι

각 요소 인덱스를 반복합니다.

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

이 에이전트 목록에서 동일한 ID를 가진 첫 번째 요소를 찾고 첫 번째 에이전트의 목록을 업데이트하여 동일한 ID임을 표시하십시오.

ILΦθ⁼κ⌕θι

남은 고유 ID 수를 계산하십시오.


5

젤리 , 25 15 바이트

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

온라인으로 사용해보십시오!

공간 분리 에이전트 클레임 목록을 가져와 별개의 스파이 수의 가장 낮은 상한을 반환하는 모나드 링크.

설명

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

이전 버전의 문제를 확인한 @Arnauld 및 @JonathanAllan과 바이트 저장을 위해 다시 @JonathanAllan에게 감사드립니다! 입력 사양이 완화되어 목록 목록을 허용하면 1 바이트가 절약됩니다.


나는 그룹의 인덱스 가 정렬되고 평평하고 중복 제거 된 필터 결과 가 반복 적용 후에 항상 정렬 된 순서로 끝날 것이기 때문에 정렬이 실제로 필요하지 않을 것이라고 생각 합니다 (예 : 결과 를 찾지 못할 것입니다) 길을 따라 나타납니다). 그래서 15 잘 될 수 있을까요? ĠfƇFQ'a a b b c', 'a b a b c[3,4,1,2]ḲĠ)ẎfƇFQɗⱮQ$ÐLL
Jonathan Allan

@JonathanAllan 좋은 자리. 나는 약간의 놀이를했고 (작동 방식을 생각하고) 당신이 옳다고 생각합니다.
Nick Kennedy

4

자바 스크립트 (Node.js) , 120 바이트

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

온라인으로 사용해보십시오!

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

껍질 , 12 바이트

LωomΣknṁoηkw

온라인으로 사용해보십시오!

설명

아이디어는 같은 사람으로 알려진 모든 스파이 그룹 목록을 만든 다음 고정 된 지점에 도달 할 때까지 교차 그룹을 점진적으로 병합하는 것입니다. 출력은 병합 할 수없는 나머지 그룹의 수입니다.

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

루비 , 123 117 바이트

movatica의 Python 3 솔루션 과 유사한 아이디어를 사용 하지만 이전에 발생한 프로파일을 추적하고 존재하는 경우 중복을 찾고 조합하여 각 "트리"에 대해 가장 낮은 스파이 인덱스를 약간 다른 방식으로 계산합니다.

@GB에서 -6 바이트

->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}

온라인으로 사용해보십시오!

설명

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

터지거나 압축하는 대신 조옮김 할 수 있습니다.
GB


@GB 감사합니다. 배열을 영원히 바꾸기 위해 pop-zip 또는 shift-zip을 사용했습니다! 또한 사용 방법 s.split.map{|i|s.index i}이 훌륭하지만 입력 길이에 따라 엣지 케이스를 만들 수 있습니다. 이 입력은 2가 아닌 3을 반환해야합니다.
Value Ink

2

파이썬 2 , 229221 바이트

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

온라인으로 사용해보십시오!

wilkben에 8 바이트 thx .


이후 g한 번만 사용됩니다, 당신은 인라인을 정의 할 수 있을까? 파이썬에서 가능하다면 잊어 버리지 만 그것이 가능하다는 것을 기억합니다.
스티븐


1

클린 , 137 바이트

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

온라인으로 사용해보십시오!

상담원이 사용하는 문자열을 상담원 간 동일성을 방지하기 위해 표시되는 줄 번호와 연결 한 다음 위치에 대한 구가 겹치는 지 반복적으로 확인하고 결과 집합 수를 계산합니다.


0

PHP , 271 바이트

ID와 함께 "스파이 번호"를 저장할 때 ID 중 하나만 숫자이면 작동하지 않습니다. 나는 그것을 고치기가 어렵지 않을 것이라고 생각한다.

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

온라인으로 사용해보십시오!

설명

이 글을 쓰고 혼란스러워하지만 모든 테스트 사례에서 작동합니다!

$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

온라인으로 사용해보십시오!

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.