スパイが多すぎる!


38

あなたは敵のスパイの大規模なネットワークと戦っています。各スパイには、使用したい偽のIDが少なくとも1つ(場合によっては複数)あることがわかっています。実際に何人のスパイを扱っているのか知りたいのです。

幸いなことに、あなたの反知能エージェントは仕事をしていて、2つの偽のアイデンティティが実際に同じ敵スパイによって実際に制御されていることを把握できる場合あります。

それは言うことです:

  • エージェントは、2つの偽のIDの背後に同じスパイがあることを常に把握しているわけではありませんが、
  • 2つの偽のIDが同じスパイによって制御されているとエージェントから言われた場合、あなたはそれらが正しいと信じます。

エージェントメッセージ

エージェントは、どのIDが同じスパイを背後に持っているかを伝える不可解なメッセージを送信します。例:

あなたは持っている2つのエージェント5つの偽のIDをに対処します。

最初のエージェントがメッセージを送信します:

Red Red Blue Orange Orange

これは、3つのスパイがいると考えることを意味します。

  • 最初の(赤)はID 1と2を制御します
  • 2番目(青)はID 3を制御します
  • 3番目(オレンジ)はID 4と5を制御します

2番目のエージェントがメッセージを送信します。

cat dog dog bird fly

これは、4人のスパイがいると考えることを意味します。

  • 最初の1つ(猫)がIDを制御します1
  • 2番目(犬)はID 2と3を制御します
  • 3番目(鳥)はID 4を制御します
  • 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

有効です。

また、同じ単語が2つの異なるエージェントによって使用される可能性があります-それは何も意味せず、単なる偶然です、例えば:

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

氷は両方のエージェントによって使用されます- Ice最初のエージェントIceによって使用されることは、2番目のエージェントによって使用される2つの発生とは無関係です。

チャレンジ

すべてのエージェントのインテルをコンパイルし、実際に存在する敵スパイの数を把握します。(より正確には、情報が限られていることを前提に、最低の上限を取得します。)

バイト単位の最短コードが優先されます。

入出力仕様

入力は、エージェントからの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

各行を単語の配列とみなすことができますか?
アーナウルド

8
@HenryHenrinson入力を厳密にする唯一のことは、コードの先頭に短い文句を追加して、入力形式を変更することです。チャレンジ自体に実際には何も追加しません
fəˈnɛtɪk

6
そのように聞こえると、コードをゴルフする機会が増えます:)
ヘンリーヘンリンソン

17
厳密なI / O形式は、チャレンジの核心を損なうため、実際には推奨されません。たとえば、入力がスペースで区切られた単語の行の形式であることを強制する必要はありません。各行を単語のリストとして表現することもできるため(Arnauldが言ったこと)、このルールがチャレンジに追加する唯一のもの線を分割する必要がありますが、これは必ずしも課題の一部ではありません。
エリック・ザ・アウトゴルファー

2
このタイトルは、平均的なTeam Fortress 2ゲームのように聞こえます!
Tvde1

回答:


10

ハンマー0.5.116の 15バイト

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

このWolfram言語関数に解凍します(最終&は暗黙的です):

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

オンラインでお試しください!

Transpose[StringSplit @ #1]:入力リスト内の各文字列を分割し、列を取得します(スパイID)

RelationGraph[Inner[Equal, ##1, Or] &, ...]:少なくとも1つの位置が等しい場合、2つの頂点がエッジを共有するグラフを構築します(友好的なエージェントによって同じスパイとして分類される場合)

Length[ConnectedComponents[...]]:接続されたコンポーネントの数は、スパイの可能な数の上限です。


9

JavaScriptの(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のアイデンティティ制限がありますか?
Vilx-

@ Vilx-彼はBigIntに切り替えることができると思いますが、もちろんバイト数がかかります。
ニール


6

Pythonの3132の 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]、最初のプロファイルが1つに属し、2番目と4番目が別のプロファイルに、3番目と5番目が最後のプロファイルに属する3つのスパイを識別します。グループインデックスは、グループ内の最初のプロファイルのインデックスでもあります。

  2. この行列([*zip(*m...)])を転置することにより、各プロファイルのグループメンバーシップを取得します。これは、グループインデックスがプロファイルインデックスのサブセットであり、すべてのエッジがより低いまたは等しいインデックスに向かうため、有向非循環グラフを形成します。同じスパイに対応するプロファイルは、他のプロファイルへの接続のないクラスターを形成します。ただし、プロファイルインデックスは複数のグループインデックスにリンクされているため、まだパスが重複しています。

  3. 次のループを使用して、グラフを最小化し、すべてのプロファイルがツリー内の最も低いインデックス、つまりルートに直接リンクされているフラットフォレストにします。 min(min(u)for u in r if min(w)in u)

  4. 最後に、フォレスト内のルートの数、つまり自身にリンクされたインデックスを返しますreturn sum(i==...)


インデントは必要ですか?私がpythonを使用してからずっと経ちましたが、onelinersを作成できることを覚えているようです。
マークガードナー

可能ですが、ネストされた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バイト節約されます。


私は考えてソートが実際に、不必要であるから、グループ内のインデックスので、Ġフィルタ結果重複除外、ソートされ、平坦化され、fƇFQ常に、繰り返し適用した後、例えば(ソート順でこれらで終わるだろう'a a b b c', 'a b a b c、最終的に見つけることができません[3,4,1,2]、途中で表示されますが)。だからḲĠ)ẎfƇFQɗⱮQ$ÐLL15のために良いかもしれない?
ジョナサンアラン

@JonathanAllan良いスポット。私は少し遊びをして(そしてそれがどのように機能するかを考えて)、あなたが正しいと思う。
ニックケネディ

4

JavaScript(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}は素晴らしいですが、入力の長さによってはエッジケースが作成される可能性があります。この入力は3、ではない。2.返す必要があります
バリューインク

2

Pythonの2229の 221バイト

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

オンラインでお試しください!

図8は、THXにバイトwilkben


以来g、一度だけ使用されている、あなたは、インラインそれを定義することができませんでしたか?Pythonでそれが可能かどうかはちょっと忘れますが、覚えているようです。
スティーブン


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.