Xác định nếu 4 điểm tạo thành một hình vuông


29

Viết hàm lấy 4 điểm trên mặt phẳng làm đầu vào và trả về đúng nếu 4 điểm tạo thành một hình vuông. Các điểm sẽ có tọa độ tích phân với giá trị tuyệt đối <1000.

Bạn có thể sử dụng bất kỳ đại diện hợp lý nào của 4 điểm làm đầu vào. Các điểm không được cung cấp theo bất kỳ thứ tự cụ thể.

Mã ngắn nhất sẽ thắng.

Ví dụ hình vuông:

(0,0),(0,1),(1,1),(1,0)    # standard square
(0,0),(2,1),(3,-1),(1,-2)  # non-axis-aligned square
(0,0),(1,1),(0,1),(1,0)    # different order

Ví dụ không phải hình vuông:

(0,0),(0,2),(3,2),(3,0)  # rectangle
(0,0),(3,4),(8,4),(5,0)  # rhombus
(0,0),(0,0),(1,1),(0,0)  # only 2 distinct points
(0,0),(0,0),(1,0),(0,1)  # only 3 distinct points

Bạn có thể trả về đúng hoặc sai cho hình vuông suy biến (0,0),(0,0),(0,0),(0,0)


Chúng ta đang nói về điểm 3D ở đây, phải không?
gnibbler

3
@gnibbler sự "trên các máy bay" là một phần của câu hỏi làm 3D chỉ khó xảy ra.
JB

Là các điểm được đưa ra theo thứ tự?
JB

@JB, tôi đã nghĩ rằng nó có nghĩa là các điểm nằm trên một mặt phẳng, nhưng tôi đã hình dung ra một mặt phẳng trong không gian 3D vì một số lý do :)
gnibbler

1
@eBusiness: -1 mà bạn đã bỏ 11 phiếu: 7 trong số đó bị hạ.
Eelvex

Câu trả lời:


12

Python 176 90 79 byte

def S(A):c=sum(A)/4.0;return set(A)==set((A[0]-c)\*1j\*\*i+c for i in range(4))

Hàm S lấy danh sách các số phức làm đầu vào (A). Nếu chúng ta biết cả tâm và một góc của hình vuông, chúng ta có thể xây dựng lại hình vuông bằng cách xoay góc 90.180 và 270 độ quanh điểm trung tâm (c). Trên mặt phẳng phức quay 90 độ về gốc tọa độ được thực hiện bằng cách nhân điểm với i . Nếu hình dạng ban đầu của chúng ta và hình vuông được xây dựng lại có cùng một điểm thì nó phải là một hình vuông.


Một vài tối ưu hóa: 1) sử dụng "S" thay vì "is_sapes" 2) đặt tất cả trên một dòng bằng cách sử dụng; 3) lặp lại trực tiếp trên 4 hướng "cho i trong (1,1j, -1, -1j)" 4) không cần [] trong đối số đã đặt.
Keith Randall

Cảm ơn Keith. (Tôi đã bỏ qua (3) vì nó dường như có cùng độ dài với mã của tôi)
paperhorse

2
@Keith Randall - Tại sao điều này được chấp nhận khi JB có giải pháp ngắn hơn nhiều?
aaaaaaaaaaaa

1
Hai lý do. Một, J sẽ luôn luôn chiến thắng. Vì vậy, tôi muốn bình thường hóa một chút bằng ngôn ngữ. Ngoài ra, tôi thích câu trả lời này tốt hơn vì nó không gặp phải vấn đề tương tự như câu trả lời chỉ có khoảng cách trong đó các số liệu khác (phải thừa nhận, chỉ những câu phi lý) đưa ra những nhận định sai.
Keith Randall

5
@Keith Randall - Trích dẫn từ câu hỏi: "Các điểm sẽ có tọa độ tích phân" "Mã ngắn nhất sẽ thắng." Sẽ hoàn toàn tốt nếu bạn chọn các tiêu chí khác nhau để chọn câu trả lời, thậm chí là tiêu chí chủ quan, nhưng sau đó bạn nên nêu điều đó trong câu hỏi.
aaaaaaaaaaaa

13

J, 28 17 25 27

J không thực sự có chức năng, nhưng đây là một động từ đơn âm lấy một vectơ điểm từ mặt phẳng phức:

4 8 4-:#/.~&(/:~&:|&,&(-/~))

Phương pháp là sự pha trộn của Michael Spencer (chỉ hoạt động trên các độ dài giữa các đỉnh; nhưng hiện tại anh ta đang thất bại với hình thoi của tôi2) và Eelvex (kiểm tra kích thước của bộ) hoạt động. Đọc từ phải sang trái:

  • -/~ tính toán tất cả các điểm khác biệt
  • , làm phẳng
  • | trích xuất cường độ
  • /:~ sắp xếp
  • #/.~ nub và đếm
  • 4 8 4 -:phải có chính xác 4 điểm tương đương (tại 0), lớn hơn 8 một chút (chiều dài 1, cạnh), 4 lớn hơn (chiều dài sqrt 2, đường chéo)

Trình diễn:

   NB. give the verb a name for easier use
   f =: 4 8 4-:#/.~&(/:~&:|&,&(-/~))

   NB. standard square
   f 0 0j1 1j1 1
1

   NB. non-axis-aligned square
   f 0 2j1 3j_1 1j_2
1

   NB. different order
   f 0 1j1 0j1 1
1

   NB. rectangle
   f 0 0j2 3j2 3
0

   NB. rhombus 1
   f 0 3j4 8j4 5
0

   NB. rhombus 2
   f 0 1ad_60 1ad0 1ad60
0

Vì lợi ích của bộ nhớ, phương pháp trước đây của tôi (các đỉnh được yêu cầu, nhưng có thể phát hiện các đa giác thông thường theo bất kỳ thứ tự nào):

*./&(={.)&(%1&|.)&(-1&|.)

Xem lịch sử để giải thích và demo. Phương thức hiện tại có thể có thể được mở rộng sang các đa giác khác, 4 8 4trông rất giống phân phối nhị thức.


Bạn có thể liên kết với ngôn ngữ này?
Sargun Dhillon

1
@gnibbler: Tại sao không? Tôi khá chắc chắn rằng nó làm.
Eelvex

1
Trên thực tế, một hình không vuông thỏa mãn các điều kiện mà bạn kiểm tra đã tồn tại, một hình tam giác đều cộng với một điểm có độ dài cạnh từ một đỉnh của hình tam giác được đặt trên đường trung tuyến mở rộng. Nhưng câu hỏi được gọi cho đầu vào số nguyên, vì vậy tôi đoán giải pháp là ok.
aaaaaaaaaaaa

1
À, được rồi Tôi đã nghĩ đến các tam giác đều có điểm thứ 4 là tâm, nhưng điều đó bị loại trừ bởi tọa độ nguyên
gnibbler

1
Bạn có thể cắt 3 ký tự bằng cách thay đổi nó thành một định nghĩa rõ ràng: 3 :'4 8 4-:#/.~/:~|,-/~y'
isawdrones

5

Con trăn, 71 42

lambda A: len(set(A))==4 and len(set(abs(i-j)for i in A for j in A))==3

Cập nhật 1) để yêu cầu 4 điểm khác nhau (trước đây sẽ cung cấp dương tính giả cho các điểm lặp lại - có điểm nào khác không?) 2) để xác định hàm cho mỗi thông số

Đối với hình vuông, vectơ giữa hai điểm bất kỳ phải là 0 (cùng một điểm), một cạnh hoặc một đường chéo. Vì vậy, tập hợp độ lớn của các vectơ này phải có độ dài 3.

# Accepts co-ordinates as sequences of complex numbers

SQUARES=[
 (0+0j,0+1j,1+1j,1+0j),  # standard square
 (0+0j,2+1j,3-1j,1-2j),  # non-axis-aligned square
 (0+0j,1+1j,0+1j,1+0j)   # different order
]

NONSQUARES=[
 (0+0j,0+2j,3+2j,3+0j),  # rectangle
 (0+0j,3+4j,8+4j,5+0j),  # rhombus
 (0+0j,0+1j,1+1j,0+0j),   # duplicated point
 (0+0j,1+60j,1+0j,1-60j)  # rhombus 2 (J B)
] 

test = "lambda A: len(set(A))==4 and len(set(abs(i-j)for i in A for j in A))==3"
assert len(test)==71

is_square=lambda A: len(set(A))==4 and len(set(abs(i-j)for i in A for j in A))==3    

for A in SQUARES:
    assert is_square(A)

for A in NONSQUARES:
    assert not is_square(A)

Tôi nghĩ rằng câu hỏi đã nêu rõ một danh sách các điểm, và không phải là một vectơ.
Sargun Dhillon

Dương tính giả.
aaaaaaaaaaaa

1
Vậy (0 + 0j, 0 + 0j, 1 + 0j, 0 + 1j) là hình vuông?
mhagger

Hình thoi 2 của tôi không phải là 1 +/- 60j, nó giống như exp (i j pi / 3) cho các giá trị từ -1, 0, 1. Lưu ý rằng như eBusiness đã chỉ ra rằng tất cả chúng không thể là tích phân, vì vậy không thực sự trong phạm vi của câu hỏi.
JB

3

Haskell, 100 ký tự

Đây là cách tôi viết giải pháp J của JB trong Haskell. Không cố gắng làm hỏng khả năng đọc bằng cách xóa các ký tự không quan trọng, khoảng 132 ký tự:

import Data.List
d (x,y) (x',y') = (x-x')^2 + (y-y')^2
square xs = (== [4,8,4]) . map length . group . sort $ [d x y | x<-xs, y<-xs]

Bạn có thể loại bỏ nó xuống một chút đến 100 bằng cách xóa các khoảng trống thừa và đổi tên một số thứ

import Data.List
d(x,y)(a,b)=(x-a)^2+(y-b)^2
s l=(==[4,8,4]).map length.group.sort$[d x y|x<-l,y<-l]

Hãy sử dụng QuickCheck để đảm bảo rằng nó chấp nhận các hình vuông tùy ý, với một đỉnh tại (x, y) và vectơ cạnh (a, b):

prop_square (x,y) (a,b) = square [(x,y),(x+a,y+b),(x-b,y+a),(x+a-b,y+b+a)]

Dùng thử trong ghci:

ghci> quickCheck prop_square
*** Failed! Falsifiable (after 1 test):  
(0,0)
(0,0)

Ồ đúng rồi, hình vuông trống không được coi là hình vuông ở đây, vì vậy chúng tôi sẽ xem xét lại bài kiểm tra của mình:

prop_square (x,y) (a,b) =
   (a,b) /= (0,0) ==> square [(x,y),(x+a,y+b),(x-b,y+a),(x+a-b,y+b+a)]

Và thử lại lần nữa:

ghci> quickCheck prop_square
+++ OK, passed 100 tests.

1
Lưu 11 ký tự bằng cách bỏ chức năng d. s l=[4,8,4]==(map length.group.sort)[(x-a)^2+(y-b)^2|(x,y)<-l,(a,b)<-l]
Ray

3

Hệ số

Một triển khai trong ngôn ngữ lập trình Factor :

USING: kernel math math.combinatorics math.vectors sequences sets ;

: square? ( seq -- ? )
    members [ length 4 = ] [
        2 [ first2 distance ] map-combinations
        { 0 } diff length 2 =
    ] bi and ;

Và một số bài kiểm tra đơn vị:

[ t ] [
    {
        { { 0 0 } { 0 1 } { 1 1 } { 1 0 } }   ! standard square
        { { 0 0 } { 2 1 } { 3 -1 } { 1 -2 } } ! non-axis-aligned square
        { { 0 0 } { 1 1 } { 0 1 } { 1 0 } }   ! different order
        { { 0 0 } { 0 4 } { 2 2 } { -2 2 } }  ! rotated square
    } [ square? ] all?
] unit-test

[ f ] [
    {
        { { 0 0 } { 0 2 } { 3 2 } { 3 0 } }   ! rectangle
        { { 0 0 } { 3 4 } { 8 4 } { 5 0 } }   ! rhombus
        { { 0 0 } { 0 0 } { 1 1 } { 0 0 } }   ! only 2 distinct points
        { { 0 0 } { 0 0 } { 1 0 } { 0 1 } }   ! only 3 distinct points
    } [ square? ] any?
] unit-test

3

Tháng 10, 145 164

let(%)(a,b)(c,d)=(c-a)*(c-a)+(d-b)*(d-b)
let t a b c d=a%b+a%c=b%c&&d%c+d%b=b%c&&a%b=a%c&&d%c=d%b
let q(a,b,c,d)=t a b c d||t a c d b||t a b d c

Chạy như thế này:

q ((0,0),(2,1),(3,-1),(1,-2))

Hãy giải thích và giải thích một chút.

Đầu tiên chúng tôi xác định một định mức:

let norm (ax,ay) (bx,by) = (bx-ax)*(bx-ax)+(by-ay)*(by-ay)

Bạn sẽ nhận thấy rằng không có cuộc gọi đến sqrt, nó không cần thiết ở đây.

let is_square_with_fixed_layout a b c d =
  (norm a b) + (norm a c) = norm b c
  && (norm d c) + (norm d b) = norm b c
  && norm a b = norm a c
  && norm d c = norm d b

Ở đây a, b, c và d là các điểm. Chúng tôi giả định rằng những điểm này được đặt ra như thế này:

a - b
| / |
c - d

Nếu chúng ta có một hình vuông thì tất cả các điều kiện này phải giữ:

  • abc là tam giác vuông
  • bcd là một tam giác vuông
  • các cạnh nhỏ hơn của mỗi tam giác vuông có cùng định mức

Quan sát rằng những điều sau đây luôn luôn giữ:

is_square_with_fixed_layout r s t u = is_square_with_fixed_layout r t s u

Chúng tôi sẽ sử dụng điều đó để đơn giản hóa chức năng kiểm tra của chúng tôi dưới đây.

Vì đầu vào của chúng tôi không được đặt hàng, chúng tôi cũng phải kiểm tra tất cả các hoán vị. Không mất tính tổng quát, chúng ta có thể tránh hoán vị điểm đầu tiên:

let is_square (a,b,c,d) =
  is_square_with_fixed_layout a b c d
  || is_square_with_fixed_layout a c b d
  || is_square_with_fixed_layout a c d b
  || is_square_with_fixed_layout a b d c
  || is_square_with_fixed_layout a d b c
  || is_square_with_fixed_layout a d c b

Sau khi đơn giản hóa:

let is_square (a,b,c,d) =
  is_square_with_fixed_layout a b c d
  || is_square_with_fixed_layout a c d b
  || is_square_with_fixed_layout a b d c

Chỉnh sửa: làm theo lời khuyên của M.Giovannini.


Tốt đẹp. Chúng tôi chưa thấy nhiều OCaml ở đây :)
E Mườix

Sử dụng toán tử thay vì ngiảm 20 ký tự : let t a b c d=a%b+a%c=b%c&&d%c+d%b=b%c&&a%b=a%c&&d%c=d%b.
Matías Giovannini

2

Con trăn (105)

Điểm được đại diện bởi (x,y)tuples. Điểm có thể theo thứ tự bất kỳ và chỉ chấp nhận hình vuông. Tạo một danh sách, skhoảng cách theo cặp (khác không) giữa các điểm. Tổng cộng có 12 khoảng cách, trong hai nhóm duy nhất.

def f (p): s = filter (Không có, [(xz) ** 2+ (yw) ** 2for x, y in p với z, w in p]); return len (s) == 12and len ( đặt (s)) == 2

Bạn có thể rời khỏi bộ lọc và kiểm tra xem len của bộ có phải là 3. Điều này chịu cùng một vấn đề dương tính giả như câu trả lời của tôi không.
gnibbler

>>> f ([(0,0), (0,4), (2,2), (- 2,2)]) = Đúng
Sargun Dhillon

2
f([(0,0),(0,4),(2,2),(-2,2)]) là một hình vuông
gnibbler

2

Python - 42 ký tự

Có vẻ như đó là một cải tiến để sử dụng số phức cho các điểm

len(set(abs(x-y)for x in A for y in A))==3

trong đó A = [(11 + 13j), (14 + 12j), (13 + 9j), (10 + 10j)]

câu trả lời cũ:

from itertools import*
len(set((a-c)**2+(b-d)**2 for(a,b),(c,d)in combinations(A,2)))==2

Điểm được chỉ định theo bất kỳ thứ tự nào dưới dạng danh sách, ví dụ:

A = [(11, 13), (14, 12), (13, 9), (10, 10)]

>>> A=[(0,0),(0,0),(1,1),(0,0)] >>> len(set((a-c)**2+(b-d)**2 for(a,b),(c,d)in combinations(A,2)))==2 True
Sargun Dhillon

@Sargun, đó là trường hợp đặc biệt của cả lớp đầu vào không hoạt động. Tôi đang cố gắng nghĩ về một bản sửa lỗi không thổi ra kích thước của câu trả lời. Trong khi đó, có thể làm việc ra lớp chung của các trường hợp thất bại?
gnibbler

A=[(0,0),(0,4),(2,2),(-2,2)]; len(set((a-c)**2+(b-d)**2 for(a,b),(c,d)in combinations(A,2)))==2
Sargun Dhillon

@Sargun: ví dụ đó là một hình vuông.
Keith Randall

để thoát khỏi các điểm trùng lặp, bạn có thể thêm -set ([0])
Keith Randall

2

C # - không chính xác ngắn. Lạm dụng LINQ. Chọn hai kết hợp điểm khác nhau trong đầu vào, tính toán khoảng cách của chúng, sau đó xác minh rằng chính xác bốn trong số chúng bằng nhau và chỉ có một giá trị khoảng cách khác biệt. Point là một lớp có hai thành viên kép, X và Y. Có thể dễ dàng là một Tuple, nhưng meh.

var points = new List<Point>
             {
                 new Point( 0, 0 ), 
                 new Point( 3, 4 ), 
                 new Point( 8, 4 ), 
                 new Point( 5, 0 )
              };    
var distances = points.SelectMany(
    (value, index) => points.Skip(index + 1),
    (first, second) => new Tuple<Point, Point>(first, second)).Select(
        pointPair =>
        Math.Sqrt(Math.Pow(pointPair.Item2.X - pointPair.Item1.X, 2) +
                Math.Pow(pointPair.Item2.Y - pointPair.Item1.Y, 2)));
return
    distances.Any(
        d => distances.Where( p => p == d ).Count() == 4 &&
                distances.Where( p => p != d ).Distinct().Count() == 1 );

2

PHP, 82 ký tự


//$x=array of x coordinates
//$y=array of respective y coordinates
/* bounding box of a square is also a square - check if Xmax-Xmin equals Ymax-Ymin */
function S($x,$y){sort($x);sort($y);return ($x[3]-$x[0]==$y[3]-$y[0])?true:false};

//Or even better (81 chars):
//$a=array of points - ((x1,y1), (x2,y2), (x3,y3), (x4,y4))
function S($a){sort($a);return (bool)($a[3][0]-$a[0][0]-abs($a[2][1]-$a[3][1]))};

Nhưng chỉ vì hộp giới hạn là hình vuông không có nghĩa là các điểm nằm trong một hình vuông. Điều kiện cần nhưng không đủ. Xem xét (0,0), (5,5), (10,0), (0, -5). Hộp giới hạn là hình vuông (0:10, -5: 5); con số không.
Floris

2

K - 33

Bản dịch của giải pháp J của JB :

{4 8 4~#:'=_sqrt+/'_sqr,/x-/:\:x}

K chịu đựng ở đây từ những từ dành riêng của nó ( _sqr_sqrt).

Kiểm tra:

  f:{4 8 4~#:'=_sqrt+/'_sqr,/x-/:\:x}

  f (0 0;0 1;1 1;1 0)
1

  f 4 2#0 0 1 1 0 1 1 0
1

  f 4 2#0 0 3 4 8 4 5 0
0

2

Pin OCaml +, 132 ký tự

let q l=match List.group(-)[?List:(x-z)*(x-z)+(y-t)*(y-t)|x,y<-List:l;z,t<-List:l;(x,y)<(z,t)?]with[[s;_;_;_];[d;_]]->2*s=d|_->false

(nhìn, Ma, không có khoảng trắng!) Việc hiểu danh sách qdưới dạng danh sách các chỉ tiêu bình phương cho mỗi cặp điểm khác nhau không có thứ tự. Một hình vuông có bốn cạnh bằng nhau và hai đường chéo bằng nhau, độ dài bình phương của cái sau bằng hai lần chiều dài bình phương của cái trước. Vì không có các tam giác đều trong mạng nguyên nên phép thử không thực sự cần thiết, nhưng tôi bao gồm nó để hoàn thiện.

Các xét nghiệm:

q [(0,0);(0,1);(1,1);(1,0)] ;;
- : bool = true
q [(0,0);(2,1);(3,-1);(1,-2)] ;;
- : bool = true
q [(0,0);(1,1);(0,1);(1,0)] ;;
- : bool = true
q [(0,0);(0,2);(3,2);(3,0)] ;;
- : bool = false
q [(0,0);(3,4);(8,4);(5,0)] ;;
- : bool = false
q [(0,0);(0,0);(1,1);(0,0)] ;;
- : bool = false
q [(0,0);(0,0);(1,0);(0,1)] ;;
- : bool = false

2

Toán học 65 80 69 66

Kiểm tra xem số lượng khoảng cách giữa các điểm riêng biệt (không bao gồm khoảng cách từ một điểm đến chính nó) là 2 và ngắn hơn của hai không phải là 0.

h = Length@# == 2 \[And] Min@# != 0 &[Union[EuclideanDistance @@@ Subsets[#, {2}]]] &;

Sử dụng

h@{{0, 0}, {0, 1}, {1, 1}, {1, 0}}       (*standard square *)
h@{{0, 0}, {2, 1}, {3, -1}, {1, -2}}     (*non-axis aligned square *)
h@{{0, 0}, {1, 1}, {0, 1}, {1, 0}}       (*a different order *)

h@{{0, 0}, {0, 2}, {3, 2}, {3, 0}}       (* rectangle *)
h@{{0, 0}, {3, 4}, {8, 4}, {5, 0}}       (* rhombus   *)
h@{{0, 0}, {0, 0}, {1, 1}, {0, 0}}       (* only 2 distinct points *)
h@{{0, 0}, {0, 1}, {1, 1}, {0, 1}}       (* only 3 distinct points *)

Đúng
Đúng
Đúng
Sai
Sai
Sai
Sai

NB: \[And]là một nhân vật duy nhất trong Mathematica.


1
Bạn đang nói với tôi rằng Mathicala không có chức năng IsSapes tích hợp?
goodguy

2

Thạch , 8 byte

_Æm×ıḟƊṆ

Hãy thử trực tuyến!

Lấy một danh sách các số phức làm đối số dòng lệnh. In 1hoặc 0.

_Æm        Subtract mean of points from each point (i.e. center on 0)
   ×ıḟƊ    Rotate 90°, then compute set difference with original.
       Ṇ   Logical negation: if empty (i.e. sets are equal) then 1 else 0.

Đây dường như là một thử thách thú vị để hồi sinh!


1

Haskell (212)

import Data.List;j=any f.permutations where f x=(all g(t x)&&s(map m(t x)));t x=zip3 x(drop 1$z x)(drop 2$z x);g(a,b,c)=l a c==sqrt 2*l a b;m(a,b,_)=l a b;s(x:y)=all(==x)y;l(m,n)(o,p)=sqrt$(o-m)^2+(n-p)^2;z=cycle

Nỗ lực đầu tiên ngây thơ. Kiểm tra hai điều kiện sau cho tất cả các hoán vị của danh sách các điểm đầu vào (trong đó một hoán vị đã cho đại diện, giả sử, theo thứ tự theo chiều kim đồng hồ của các điểm):

  • tất cả các góc là 90 độ
  • tất cả các cạnh đều có cùng chiều dài

Mã khử và kiểm tra

j' = any satisfyBothConditions . permutations
          --f
    where satisfyBothConditions xs = all angleIs90 (transform xs) && 
                                     same (map findLength' (transform xs))
          --t
          transform xs = zip3 xs (drop 1 $ cycle xs) (drop 2 $ cycle xs)
          --g
          angleIs90 (a,b,c) = findLength a c == sqrt 2 * findLength a b
          --m
          findLength' (a,b,_) = findLength a b
          --s
          same (x:xs) = all (== x) xs
          --l
          findLength (x1,y1) (x2,y2) = sqrt $ (x2 - x1)^2 + (y2 - y1)^2


main = do print $ "These should be true"
          print $ j [(0,0),(0,1),(1,1),(1,0)]
          print $ j [(0,0),(2,1),(3,-1),(1,-2)]
          print $ j [(0,0),(1,1),(0,1),(1,0)]
          print $ "These should not"
          print $ j [(0,0),(0,2),(3,2),(3,0)]
          print $ j [(0,0),(3,4),(8,4),(5,0)]
          print $ "also testing j' just in case"
          print $ j' [(0,0),(0,1),(1,1),(1,0)]
          print $ j' [(0,0),(2,1),(3,-1),(1,-2)]
          print $ j' [(0,0),(1,1),(0,1),(1,0)]
          print $ j' [(0,0),(0,2),(3,2),(3,0)]
          print $ j' [(0,0),(3,4),(8,4),(5,0)]

1

Scala (146 ký tự)

def s(l:List[List[Int]]){var r=Set(0.0);l map(a=>l map(b=>r+=(math.pow((b.head-a.head),2)+math.pow((b.last-a.last),2))));print(((r-0.0).size)==2)}

1

JavaScript 144 ký tự

Về mặt toán học tương đương với câu trả lời của J Bs. Nó tạo ra 6 độ dài và khẳng định rằng 2 lớn nhất bằng nhau và 4 nhỏ nhất bằng nhau. Đầu vào phải là một mảng của mảng.

function F(a){d=[];g=0;for(b=4;--b;)for(c=b;c--;d[g++]=(e*e+f*f)/1e6)e=a[c][0]-a[b][0],f=a[c][1]-a[b][1];d.sort();return d[0]==d[3]&&d[4]==d[5]} //Compact function
testcases=[
[[0,0],[1,1],[1,0],[0,1]],
[[0,0],[999,999],[999,0],[0,999]],
[[0,0],[2,1],[3,-1],[1,-2]],
[[0,0],[0,2],[3,2],[3,0]],
[[0,0],[3,4],[8,4],[5,0]],
[[0,0],[0,0],[1,1],[0,0]],
[[0,0],[0,0],[1,0],[0,1]]
]
for(v=0;v<7;v++){
    document.write(F(testcases[v])+"<br>")
}

function G(a){ //Readable version
    d=[]
    g=0
    for(b=4;--b;){
        for(c=b;c--;){
            e=a[c][0]-a[b][0]
            f=a[c][1]-a[b][1]
            d[g++]=(e*e+f*f)/1e6 //The division tricks the sort algorithm to sort correctly by default method.
        }
    }
    d.sort()
    return (d[0]==d[3]&&d[4]==d[5])
}

1

PHP, 161 158 ký tự

function S($a){for($b=4;--$b;)for($c=$b;$c--;){$e=$a[$c][0]-$a[$b][0];$f=$a[$c][1]-$a[$b][1];$d[$g++]=$e*$e+$f*$f;}sort($d);return$d[0]==$d[3]&&$d[4]==$d[5];}

Bằng chứng (1x1): http://codepad.viper-7.com/ZlBpOB

Điều này dựa trên câu trả lời JavaScript của eBuisness .


Có một chút không rõ ràng từ tuyên bố vấn đề, các điểm sẽ được sắp xếp theo thứ tự. Tôi sẽ đi hỏi.
JB

1
Tôi không nghĩ rằng điều này sẽ xử lý đúng nhiều trường hợp. Ví dụ, nó sẽ dán nhãn hình thoi không chính xác thành hình vuông.
Keith Randall

Đã cập nhật điều này để phù hợp với một trong các câu trả lời JavaScript, nên xử lý tất cả các trường hợp.
Kevin Brown

1

JavaScript 1.8, 112 ký tự

Cập nhật: lưu 2 ký tự bằng cách gấp các mảng hiểu với nhau.

function i(s)(p=[],[(e=x-a,f=y-b,d=e*e+f*f,p[d]=~~p[d]+1)for each([a,b]in s)for each([x,y]in s)],/8,+4/.test(p))

Một lần nữa thực hiện câu trả lời của JB. Khai thác các tính năng JavaScript 1.7 / 1.8 (đóng biểu thức, hiểu mảng, gán hủy). Cũng lạm dụng ~~(nhân đôi bit không phải toán tử) để ép buộc undefinedthành số, với ép buộc theo chuỗi và một biểu thức chính quy để kiểm tra xem số lượng chiều dài có [4, 8, 4](giả định rằng chính xác 4 điểm được thông qua). Việc lạm dụng toán tử dấu phẩy là một thủ thuật C bị xáo trộn cũ.

Các xét nghiệm:

function assert(cond, x) { if (!cond) throw ["Assertion failure", x]; }

let text = "function i(s)(p=[],[(e=x-a,f=y-b,d=e*e+f*f,p[d]=~~p[d]+1)for each([a,b]in s)for each([x,y]in s)],/8,+4/.test(p))"
assert(text.length == 112);
assert(let (source = i.toSource()) (eval(text), source == i.toSource()));

// Example squares:
assert(i([[0,0],[0,1],[1,1],[1,0]]))    // standard square
assert(i([[0,0],[2,1],[3,-1],[1,-2]]))  // non-axis-aligned square
assert(i([[0,0],[1,1],[0,1],[1,0]]))    // different order

// Example non-squares:
assert(!i([[0,0],[0,2],[3,2],[3,0]]))  // rectangle
assert(!i([[0,0],[3,4],[8,4],[5,0]]))  // rhombus
assert(!i([[0,0],[0,0],[1,1],[0,0]]))  // only 2 distinct points
assert(!i([[0,0],[0,0],[1,0],[0,1]]))  // only 3 distinct points

// Degenerate square:
assert(!i([[0,0],[0,0],[0,0],[0,0]]))   // we reject this case

1

GoRuby - 66 ký tự

f=->a{z=12;a.pe(2).m{|k,l|(k-l).a}.so.go{|k|k}.a{|k,l|l.sz==z-=4}}

mở rộng:

f=->a{z=12;a.permutation(2).map{|k,l|(k-l).abs}.sort.group_by{|k|k}.all?{|k,l|l.size==(z-=4)}}

Thuật toán tương tự như câu trả lời của JB .

Kiểm tra như:

p f[[Complex(0,0), Complex(0,1), Complex(1,1), Complex(1,0)]]

Đầu ra truecho đúng và trống cho sai


Chưa bao giờ nghe nói về GoRuby. Có bất cứ điều gì chính thức viết về nó? stackoverflow.com/questions/63998/hidden-features-of-ruby/ory
Jonas Elfström

@Jonas: Tôi chưa thấy bất cứ điều gì thực sự chính thức về nó, bài đăng blog tốt nhất tôi đã thấy là bài này . Tôi thực sự không thể làm cho nó được xây dựng và hoạt động nhưng một giải pháp thay thế là chỉ sao chép khúc dạo đầu vào cùng một thư mục và chạy ruby -r ./golf-prelude.rb FILE_TO_RUN.rbvà nó sẽ hoạt động tương tự.
Nemo157

nó không phải là cần thiết để sorttrước group_by. .sort.group_by {...}nên được viết là.group_by {...}
user102008

1

Python 97 (không có điểm phức tạp)

def t(p):return len(set(p))-1==len(set([pow(pow(a-c,2)+pow(b-d,2),.5)for a,b in p for c,d in p]))

Điều này sẽ lấy danh sách các bộ điểm theo [(x, y), (x, y), (x, y), (x, y)] theo bất kỳ thứ tự nào và có thể xử lý các điểm trùng lặp hoặc sai số điểm. Nó KHÔNG yêu cầu các điểm phức tạp như các câu trả lời trăn khác.

Bạn có thể kiểm tra nó như thế này:

S1 = [(0,0),(1,0),(1,1),(0,1)]   # standard square
S2 = [(0,0),(2,1),(3,-1),(1,-2)] # non-axis-aligned square
S3 = [(0,0),(1,1),(0,1),(1,0)]   # different order
S4 = [(0,0),(2,2),(0,2),(2,0)]   #
S5 = [(0,0),(2,2),(0,2),(2,0),(0,0)] #Redundant points

B1 = [(0,0),(0,2),(3,2),(3,0)]  # rectangle
B2 = [(0,0),(3,4),(8,4),(5,0)]  # rhombus
B3 = [(0,0),(0,0),(1,1),(0,0)]  # only 2 distinct points
B4 = [(0,0),(0,0),(1,0),(0,1)]  # only 3 distinct points
B5 = [(1,1),(2,2),(3,3),(4,4)]  # Points on the same line
B6 = [(0,0),(2,2),(0,2)]        # Not enough points

def tests(f):
    assert(f(S1) == True)
    assert(f(S2) == True)
    assert(f(S3) == True)
    assert(f(S4) == True)
    assert(f(S5) == True)

    assert(f(B1) == False)
    assert(f(B2) == False)
    assert(f(B3) == False)
    assert(f(B4) == False)
    assert(f(B5) == False)
    assert(f(B6) == False)

def t(p):return len(set(p))-1==len(set([pow(pow(a-c,2)+pow(b-d,2),.5)for a,b in p for c,d in p]))

tests(t)

Điều này sẽ giải thích một chút, nhưng ý tưởng tổng thể là chỉ có ba khoảng cách giữa các điểm trong một hình vuông (Cạnh, Đường chéo, Không (điểm so với chính nó)):

def t(p):return len(set(p))-1==len(set([pow(pow(a-c,2)+pow(b-d,2),.5)for a,b in p for c,d in p]))
  • cho một danh sách p của các bộ dữ liệu (x, y)
  • Loại bỏ trùng lặp bằng cách sử dụng bộ (p) và sau đó kiểm tra độ dài
  • Lấy mọi tổ hợp điểm (a, b in p cho c, d trong p)
  • Nhận danh sách khoảng cách từ mọi điểm đến mọi điểm khác
  • Sử dụng thiết lập để kiểm tra chỉ có ba khoảng cách duy nhất - Không (điểm so với chính nó) - Độ dài cạnh - Độ dài đường chéo

Để lưu ký tự mã tôi là:

  • sử dụng tên hàm 1 char
  • sử dụng định nghĩa hàm 1 dòng
  • Thay vì kiểm tra số điểm duy nhất là 4, tôi kiểm tra xem đó là -1 độ dài điểm khác nhau (lưu == 3 ==)
  • sử dụng danh sách và bộ giải nén để lấy a, b in p cho c, d trong p, thay vì sử dụng [0], a [1]
  • sử dụng pow (x, .5) thay vì bao gồm toán học để có sqrt (x)
  • không đặt dấu cách sau)
  • không đặt số 0 đứng đầu

Tôi sợ ai đó có thể tìm thấy một trường hợp thử nghiệm phá vỡ điều này. Vì vậy, xin vui lòng làm và Ill đúng. Ví dụ, thực tế tôi chỉ kiểm tra ba khoảng cách, thay vì thực hiện abs () và kiểm tra độ dài cạnh và cạnh huyền, có vẻ như là một lỗi.

Lần đầu tiên tôi đã thử chơi golf code. Hãy tử tế nếu tôi phá vỡ bất kỳ quy tắc nhà.


1

Clojure, 159 ký tự.

user=> (def squares
         [[[0,0] [0,1] [1,1]  [1,0]]   ; standard square
         [[0,0] [2,1] [3,-1] [1,-2]]  ; non-axis-aligned square
         [[0,0] [1,1] [0,1]  [1,0]]]) ; different order
#'user/squares
user=> (def non-squares
         [[[0,0] [0,2] [3,2] [3,0]]    ; rectangle
          [[0,0] [3,4] [8,4] [5,0]]])  ; rhombus
#'user/non-squares
user=> (defn norm
         [x y]
         (reduce + (map (comp #(* % %) -) x y)))
#'user/norm
user=> (defn square?
         [[a b c d]]
         (let [[x y z] (sort (map #(norm a %) [b c d]))]
           (and (= x y) (= z (* 2 x)))))
#'user/square?
user=> (every? square? squares)
true
user=> (not-any? square? non-squares)
true

Chỉnh sửa: Để cũng giải thích một chút.

  • Đầu tiên xác định một định mức về cơ bản cho khoảng cách giữa hai điểm đã cho.
  • Sau đó tính khoảng cách của điểm đầu tiên đến ba điểm còn lại.
  • Sắp xếp ba khoảng cách. (Điều này cho phép bất kỳ thứ tự nào của các điểm.)
  • Hai khoảng cách ngắn nhất phải bằng một hình vuông.
  • Khoảng cách thứ ba (dài nhất) phải bằng căn bậc hai của tổng bình phương của khoảng cách ngắn theo định lý Pythagoras.

(Lưu ý: không cần root vuông và do đó trong mã được lưu ở trên.)


1

C #, 107 ký tự

return p.Distinct().Count()==4&&
(from a in p from b in p select (a-b).LengthSquared).Distinct().Count()==3;

Trong đó điểm là Danh sách Vector3D chứa các điểm.

Tính tất cả các khoảng cách bình phương giữa tất cả các điểm và nếu có chính xác ba loại riêng biệt (phải là 0, một số giá trị a và 2 * a) và 4 điểm khác biệt thì các điểm tạo thành một hình vuông.



1

Python 2 , 49 byte

lambda l:all(1j*z+(1-1j)*sum(l)/4in l for z in l)

Hãy thử trực tuyến!

Đưa ra một danh sách bốn số phức làm đầu vào. Xoay mỗi điểm 90 độ quanh mức trung bình và kiểm tra xem mỗi điểm kết quả có trong danh sách ban đầu không.

Cùng độ dài (mặc dù ngắn hơn trong Python 3 bằng cách sử dụng {*l}).

lambda l:{1j*z+(1-1j)*sum(l)/4for z in l}==set(l)

Hãy thử trực tuyến!


Tại sao không sử dụng Python 3 nếu nó ngắn hơn? Ngoài ra, nếu nó được phép trả về các giá trị trung thực / giả tùy ý trong Python, ^có thể được sử dụng thay thế ==.
Joel

@Joel Python 2 chủ yếu là ưu tiên và đây là một thử thách thực sự cũ từ năm 2011 khi Python 2 được chơi golf Python khá nhiều. Và thách thức nói trả lại đúng hay sai, vì vậy tôi mắc kẹt với điều đó. Nếu điều này được đăng ngày hôm nay, nó có thể sẽ chỉ định xuất ra sự thật / falsey hoặc một trong hai giá trị riêng biệt và thậm chí có thể chấp nhận điều đó theo mặc định.
xnor

1

Ngôn ngữ Wolfram (Mathicala) , 32 31 byte

Tr[#^2]==Tr[#^3]==0&[#-Mean@#]&

Hãy thử trực tuyến!

Đưa ra một danh sách các điểm được biểu thị bằng số phức, tính toán thời điểm trung tâm thứ hai và thứ ba và kiểm tra xem cả hai đều bằng không.

Chưa chơi gôn:

S[p_] := Total[(p - Mean[p])^2] == Total[(p - Mean[p])^3] == 0

hoặc là

S[p_] := CentralMoment[p, 2] == CentralMoment[p, 3] == 0

bằng chứng

Tiêu chí này hoạt động trên toàn bộ mặt phẳng phức, không chỉ trên các số nguyên Gaussian .

  1. Đầu tiên, chúng tôi lưu ý rằng các khoảnh khắc trung tâm không thay đổi khi các điểm được dịch cùng nhau. Cho một tập hợp các điểm

    P = Table[c + x[i] + I*y[i], {i, 4}]
    

    những khoảnh khắc trung tâm đều độc lập với c(đó là lý do tại sao chúng được gọi là trung tâm ):

    {FreeQ[FullSimplify[CentralMoment[P, 2]], c], FreeQ[FullSimplify[CentralMoment[P, 3]], c]}
    (*    {True, True}    *)
    
  2. Thứ hai, các khoảnh khắc trung tâm có một sự phụ thuộc đơn giản vào tỷ lệ tổng thể phức tạp (chia tỷ lệ và xoay) của tập hợp các điểm:

    P = Table[f * (x[i] + I*y[i]), {i, 4}];
    FullSimplify[CentralMoment[P, 2]]
    (*    f^2 * (...)    *)
    FullSimplify[CentralMoment[P, 3]]
    (*    f^3 * (...)    *)
    

    Điều này có nghĩa là nếu một khoảnh khắc trung tâm bằng 0, thì tỷ lệ và / hoặc xoay tập hợp các điểm sẽ giữ cho thời điểm trung tâm bằng không.

  3. Thứ ba, hãy chứng minh tiêu chí cho một danh sách các điểm trong đó hai điểm đầu tiên được cố định:

    P = {0, 1, x[3] + I*y[3], x[4] + I*y[4]};
    

    Trong những điều kiện nào là phần thực và phần ảo của khoảnh khắc trung tâm thứ hai và thứ ba bằng không?

    C2 = CentralMoment[P, 2] // ReIm // ComplexExpand // FullSimplify;
    C3 = CentralMoment[P, 3] // ReIm // ComplexExpand // FullSimplify;
    Solve[Thread[Join[C2, C3] == 0], {x[3], y[3], x[4], y[4]}, Reals] // FullSimplify
    (*    {{x[3] -> 0, y[3] -> -1, x[4] -> 1, y[4] -> -1},
           {x[3] -> 0, y[3] -> 1, x[4] -> 1, y[4] -> 1},
           {x[3] -> 1/2, y[3] -> -1/2, x[4] -> 1/2, y[4] -> 1/2},
           {x[3] -> 1/2, y[3] -> 1/2, x[4] -> 1/2, y[4] -> -1/2},
           {x[3] -> 1, y[3] -> -1, x[4] -> 0, y[4] -> -1},
           {x[3] -> 1, y[3] -> 1, x[4] -> 0, y[4] -> 1}}    *)
    

    Tất cả sáu giải pháp này đại diện cho hình vuông: nhập mô tả hình ảnh ở đây Do đó, cách duy nhất mà một danh sách các điểm {0, 1, x[3] + I*y[3], x[4] + I*y[4]}có dạng có thể có các giây trung tâm thứ hai và thứ ba là khi bốn điểm tạo thành một hình vuông.

Do các đặc tính dịch, xoay và chia tỷ lệ được thể hiện ở các điểm 1 và 2, điều này có nghĩa là bất cứ khi nào khoảnh khắc trung tâm thứ hai và thứ ba bằng 0, chúng ta có một hình vuông ở một số trạng thái dịch / xoay / chia tỷ lệ. ■

khái quát hóa

Khoảnh khắc trung tâm thứ k của một n-gon thông thường bằng 0 nếu k không chia hết cho n. Đủ các điều kiện này phải được kết hợp để tạo thành một tiêu chí đủ để phát hiện n-gon. Đối với trường hợp n = 4, nó đủ để phát hiện các số không trong k = 2 và k = 3; để phát hiện, ví dụ, hình lục giác (n = 6) có thể cần phải kiểm tra k = 2,3,4,5 cho các số không. Tôi đã không chứng minh những điều sau đây, nhưng nghi ngờ rằng nó sẽ phát hiện bất kỳ n-gon thông thường nào:

isregularngon[p_List] :=
  And @@ Table[PossibleZeroQ[CentralMoment[p, k]], {k, 2, Length[p] - 1}]

Thử thách mã về cơ bản là mã này chuyên cho các danh sách dài 4.


Giải pháp có vẻ khá thú vị. Bạn có thể giải thích tại sao nó đưa ra câu trả lời chính xác?
Joel

@Joel Tôi đã thêm một bằng chứng.
La Mã

Cảm ơn rất nhiều. Sẽ là lý tưởng khi có thể có một lời giải thích toán học trực quan hơn về giải pháp tốt đẹp này.
Joel

@Joel Tôi có thể cung cấp cho bạn chủ đề dẫn tôi đến giải pháp này. Tôi bắt đầu bằng cách nhận thấy rằng các hình vuông (như danh sách tọa độ, không phải số phức) có ma trận hiệp phương sai tỷ lệ với ma trận đơn vị; tuy nhiên, điều kiện này là không đủ (dương tính giả). Khoảnh khắc trung tâm thứ ba phải bằng không đối với bất kỳ cấu trúc đối xứng điểm nào. Vì vậy, tôi chuyển sang biểu diễn phức tạp để đặt một điều kiện vào khoảnh khắc trung tâm thứ hai và thứ ba, và thật ngạc nhiên, hóa ra khoảnh khắc trung tâm thứ hai là không đối với hình vuông.
La Mã

Tuyệt quá. Cảm ơn đã chỉ ra đường dẫn đến giải pháp này.
Joel

0

J, 31 29 27 26

3=[:#[:~.[:,([:+/*:@-)"1/~

kiểm tra xem 8 khoảng cách nhỏ nhất giữa các điểm có giống nhau không. kiểm tra xem có chính xác ba loại khoảng cách giữa các điểm (không, độ dài cạnh và chiều dài đường chéo).

f 4 2 $ 0 0 2 1 3 _1 1 _2
1
f 4 2 $ 0 0 0 2 3 2 3 0
0

4 2 $ là một cách viết một mảng trong J.


Điều này thất bại trong bài kiểm tra hình thoi.
JB

@JB: Tôi bị lỗi đánh máy. Bây giờ tôi đã thay đổi phương pháp.
Eelvex

Eeew ... bạn đang dùng cùng một phương pháp mà tôi đã ăn cắp. Ngoại trừ phiên bản ngắn hơn của tôi: p
JB

@JB: thật sao? Tôi đã không nhận thấy điều đó. Ai khác kiểm tra (3 == #distances)?
Eelvex

@JB: oic ... một số kiểm tra kết hợp của 2 .: - /
E Mườix

0

Smalltalk cho 106 ký tự

s:=Set new.
p permutationsDo:[:e|s add:((e first - e second) dotProduct:(e first - e third))].
s size = 2

Trong đó p là tập hợp các điểm, vd

p := { 0@0. 2@1. 3@ -1. 1@ -2}. "twisted square"

Tôi nghĩ rằng toán học là âm thanh ...


Kiểm tra 2 sản phẩm chấm khác biệt không cắt nó. Các điểm được đặt ở cùng một vị trí có thể tạo ra dương tính giả.
aaaaaaaaaaaa

0

Mathicala, 123 ký tự (nhưng bạn có thể làm tốt hơn):

Flatten[Table[x-y,{x,a},{y,a}],1]
Sort[DeleteDuplicates[Abs[Flatten[Table[c.d,{c,%},{d,%}]]]]]
%[[1]]==0&&%[[3]]/%[[2]]==2

Trong đó 'a' là đầu vào ở dạng danh sách Mathicala, ví dụ: a={{0,0},{3,4},{8,4},{5,0}}

Điều quan trọng là xem xét các sản phẩm chấm giữa tất cả các vectơ và lưu ý rằng chúng phải có chính xác ba giá trị: 0, x và 2 * x đối với một số giá trị của x. Sản phẩm chấm kiểm tra cả độ vuông góc VÀ chiều dài trong một lần phồng.

Tôi biết có những phím tắt Mathicala có thể làm cho nó ngắn hơn, nhưng tôi không biết chúng là gì.


Tôi nghĩ rằng điều này là sai, nhưng tôi không thể tìm ra những gì mã làm.
aaaaaaaaaaaa

Nó tính toán tất cả các vectơ giữa 4 điểm, lấy tất cả các sản phẩm chấm (giá trị tuyệt đối) và hy vọng kết quả sẽ bao gồm chính xác 0, x, 2 * x cho một số giá trị của x.
barrycarter

Vì vậy, 16 vectơ -> 256 chấm sản phẩm và bạn kiểm tra xem giá trị cao gấp 2 lần mức thấp, nhưng bạn không biết có bao nhiêu giá trị của mỗi giá trị. Điều đó có đúng không?
aaaaaaaaaaaa

Vâng, điều đó mô tả chính xác thuật toán của tôi. Và bây giờ tôi nghĩ bạn đúng: bạn có thể xây dựng một kịch bản trong đó cả 3 giá trị xảy ra, nhưng không đúng số lượng. Chuột Có nên sửa chữa mặc dù?
barrycarter

@barrycarter Bạn có thể lưu các ký tự bằng cách sử dụng Unionthay vì Sort@DeleteDuplicates. Tôi cũng ghép 3 dòng của bạn lại:#[[1]] == 0 && #[[3]]/#[[2]] == 2 &[ Union@Abs@Flatten[Table[c.d, {c, #}, {d, #}]] &[ Flatten[Table[x - y, {x, a}, {y, a}], 1]]]
DavidC

0

Haskell, "wc -c" báo cáo 110 ký tự. Không kiểm tra xem đầu vào có 4 phần tử.

import Data.List
k [a,b]=2*a==b
k _=0<1
h ((a,b):t)=map (\(c,d)->(a-c)^2+(b-d)^2) t++h t
h _=[]
j=k.nub.sort.h

Tôi đã thử nghiệm trên

test1 = [(0,0),(3,4),(-4,3),(-1,7)] -- j test1 is True
test2 = [(0,0),(3,4),(-3,4),(0,8)]  -- j test2 is False

Lưu ý ở trên không bao giờ có khoảng cách từ một điểm đến chính nó, vì vậy sự hiện diện của khoảng cách 0 sẽ chỉ ra một điểm lặp lại trong danh sách đầu vào và điều này sẽ hiển thị trong danh sách được sắp xếp là k [0, b] vì vậy 2 * 0 == b sẽ luôn thất bại vì b không thể giống như 0.
Chris Kuklewicz
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.