สายลับมากเกินไป!


38

คุณกำลังต่อสู้กับเครือข่ายสายลับของศัตรูมากมาย คุณรู้ว่าสายลับแต่ละอันมีตัวตนปลอมอย่างน้อยหนึ่ง (หลายครั้ง) ที่พวกเขาต้องการใช้ คุณต้องการทราบจำนวนสายลับที่คุณกำลังเผชิญอยู่จริง ๆ

โชคดีที่หน่วยสืบราชการลับของคุณตัวแทนกำลังทำงานของพวกเขาและสามารถบางครั้งคิดออกเมื่อสองปลอมจะถูกควบคุมจริงโดยสอดแนมศัตรูเดียวกัน

กล่าวคือ:

  • ตัวแทนของคุณไม่ทราบว่าเมื่อใดที่ตัวปลอมสองตัวมีสายลับเดียวกันอยู่ข้างหลังพวกเขา
  • หากตัวแทนแจ้งให้คุณทราบว่าตัวตนปลอมสองตัวนั้นถูกควบคุมโดยสายลับเดียวกันคุณเชื่อว่าพวกเขาถูกต้อง

ข้อความตัวแทน

ตัวแทนส่งข้อความลับ ๆ ให้คุณเพื่อบอกคุณว่าตัวตนใดที่มีสายลับเดียวกันข้างหลังพวกเขา ตัวอย่าง:

คุณมี2 ตัวแทนและตัวปลอม 5 ตัวที่จะจัดการ

ตัวแทนแรกส่งข้อความถึงคุณ:

Red Red Blue Orange Orange

หมายความว่าพวกเขาคิดว่ามีสายลับ 3:

  • อันแรก (สีแดง) ควบคุมข้อมูลประจำตัว 1 และ 2
  • ตัวที่สอง (สีน้ำเงิน) ควบคุมเอกลักษณ์ 3
  • อันที่สาม (สีส้ม) ควบคุมเอกลักษณ์ 4 และ 5

เอเจนต์ที่สองส่งข้อความถึงคุณ:

cat dog dog bird fly

หมายความว่าพวกเขาคิดว่ามีสายลับ 4:

  • ตัวแรก (cat) ควบคุมเอกลักษณ์ 1
  • ตัวที่สอง (สุนัข) ควบคุมเอกลักษณ์ 2 และ 3
  • ตัวที่สาม (นก) ควบคุมเอกลักษณ์ 4
  • อันที่สี่ (บิน) ควบคุมเอกลักษณ์ 5

รวบรวม Intel ที่เราเห็น:

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

วิธีการนี้มีที่มากที่สุด2 สายลับ

หมายเหตุ

เอกลักษณ์ที่เป็นเจ้าของโดยสายลับเดียวกันไม่จำเป็นต้องต่อเนื่องกันเช่นข้อความเช่น:

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 Julnɛtɪk

6
เสียงที่ฉันชอบที่จะให้โอกาสมากขึ้นในการเล่นกอล์ฟรหัส :)
เฮนรี่ Henrinson

17
รูปแบบ I / O ที่เข้มงวดนั้นเป็นสิ่งที่ทำให้หมดกำลังใจเพราะมันเบี่ยงเบนความสนใจ ตัวอย่างเช่นการบังคับให้อินพุตเป็นรูปแบบของคำที่คั่นด้วยช่องว่างไม่จำเป็นเนื่องจากหนึ่งสามารถแสดงแต่ละบรรทัดเป็นรายการของคำ (สิ่งที่ Arnauld พูด) และสิ่งเดียวที่กฎนี้เพิ่มความท้าทาย เป็นความจำเป็นที่จะต้องแบ่งบรรทัดบางสิ่งที่ไม่จำเป็นต้องเป็นส่วนหนึ่งของความท้าทาย
Erik the Outgolfer

2
ชื่อนี้ดูเหมือนว่าเกม Team Fortress 2 โดยเฉลี่ยของคุณ!
Tvde1

คำตอบ:


10

Sledgehammer 0.5.1 , 16 15 ไบต์

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

คลายการบีบอัดในฟังก์ชั่นภาษา Wolfram (สุดท้าย&คือ implicit):

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

ลองออนไลน์!

Transpose[StringSplit @ #1]: แยกแต่ละสตริงในรายการอินพุตและนำคอลัมน์ (ข้อมูลประจำตัวสอดแนม)

RelationGraph[Inner[Equal, ##1, Or] &, ...]: สร้างกราฟที่จุดยอดสองจุดใช้ขอบหากตำแหน่งอย่างน้อยหนึ่งตำแหน่งเท่ากัน (หากจำแนกเป็นสายลับเดียวกันโดยตัวแทนที่เป็นมิตร)

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 ได้แม้ว่าจะต้องเสียค่าใช้จ่ายเป็นจำนวนไบต์แน่นอน
Neil


6

Python 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)]สำหรับตัวแทนแต่ละเราสร้างแผนที่ของโปรไฟล์และนามแฝงของพวกเขาซึ่งเป็นดัชนีต่ำสุดของลักษณะ: Ie [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==...).


เยื้องจึงจำเป็นหรือไม่ เป็นเวลานานแล้วที่ฉันใช้หลาม แต่ฉันจำได้ว่าคุณสามารถสร้างผู้บุกรุกได้
Mark Gardner

คุณสามารถ แต่ไม่ได้ถ้าคุณใช้ซ้อนกันสำหรับลูป TIO สำหรับตัวคุณเอง;)
movatica

5

ถ่าน , 49 43 ไบต์

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

ลองออนไลน์! การเชื่อมโยงคือการใช้รหัสเวอร์ชันอย่างละเอียด สามารถบันทึกสองสามไบต์โดยใช้รูปแบบอินพุตที่ยุ่งยาก คำอธิบาย:

≔⪪S θ

ป้อนรายชื่อตัวแทนแรก

WS«

ทำซ้ำสำหรับตัวแทนที่เหลืออยู่

≔⪪ι ι

ใส่รายการของพวกเขา

FLι

วนรอบแต่ละดัชนีองค์ประกอบ

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

ค้นหาองค์ประกอบแรกในรายการของตัวแทนนี้ด้วยข้อมูลเฉพาะตัวเดียวกันและอัปเดตรายการตัวแทนแรกเพื่อแสดงว่าเป็นข้อมูลเฉพาะตัวเดียวกัน

ILΦθ⁼κ⌕θι

นับจำนวนตัวตนที่ไม่ซ้ำกันที่เหลืออยู่


5

เยลลี่ , 25 15 ไบต์

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

ลองออนไลน์!

ลิงก์ monadic ที่ใช้รายการการเคลมเอเจนต์ space-separates และส่งคืนขอบเขตบนสุดของจำนวนสายลับที่แตกต่างกัน

คำอธิบาย

  )              | 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 อีกครั้งสำหรับการบันทึกไบต์! หากข้อมูลจำเพาะอินพุตผ่อนคลายเพื่ออนุญาตรายการรายการสิ่งนี้จะบันทึกหนึ่งไบต์


ฉันคิดว่าการเรียงลำดับอาจไม่จำเป็นเนื่องจากดัชนีในกลุ่มจากการĠเรียงลำดับและผลลัพธ์การกรองที่ไม่ซ้ำกันจะถูกแบนfƇFQหลังจากการใช้ซ้ำหลายครั้งจบลงด้วยการเรียงลำดับเหล่านี้ (เช่น'a a b b c', 'a b a b cจะไม่พบในที่สุด[3,4,1,2]แม้ว่ามันจะปรากฏขึ้นตลอดทาง) ดังนั้นḲĠ)ẎfƇFQɗⱮQ$ÐLLอาจจะดีสำหรับ 15
Jonathan Allan

@ โจนาธานจุดดีมาก ฉันเคยเล่นบ้าง (และคิดว่ามันทำงานอย่างไร) และคิดว่าคุณพูดถูก
Nick Kennedy

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

Huskขนาด 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

Ruby , 123 117 ไบต์

ใช้แนวคิดที่คล้ายกันกับโซลูชัน Python 3 ของ movaticaแต่คำนวณดัชนีสายลับต่ำสุดสำหรับ "ต้นไม้" แต่ละอันด้วยวิธีที่แตกต่างกันเล็กน้อย (โดยการติดตามโปรไฟล์ที่พบก่อนหน้านี้ค้นหาการซ้อนทับหากมีอยู่และรวมเข้าด้วยกัน)

-6 ไบต์จาก @GB

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

แทนการ popping และซิปคุณสามารถเปลี่ยนได้
GB


@GB ขอบคุณสำหรับหัวขึ้น; ฉันใช้ pop-zip หรือ shift-zip เพื่อย้ายอาร์เรย์ไปตลอดกาล! เคล็ดลับในการใช้งานของคุณs.split.map{|i|s.index i}นั้นดี แต่มันสามารถสร้างเคสแบบขอบได้ตามความยาวของอินพุต ข้อมูลนี้ควรส่งคืน 3 ไม่ใช่ 2
หมึกมูลค่า

2

Python 2 , 229 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 ไบต์ขอบคุณไปwilkben


เนื่องจากgใช้เพียงครั้งเดียวคุณไม่สามารถกำหนดแบบอินไลน์ได้หรือไม่ ฉันลืมว่าเป็นไปได้ใน Python แต่ดูเหมือนว่าจะจำได้
Stephen


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 ไบต์

สิ่งนี้จะไม่ทำงานหากข้อมูลประจำตัวใด ๆ เป็นเพียงตัวเลขในขณะที่ฉันเก็บ "หมายเลขสปาย" ไว้ในข้อมูลประจำตัว ฉันไม่คิดว่ามันคงไม่ยากที่จะแก้ไข

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