Chiến lược tối ưu cho một trò chơi trừu tượng


12

Tôi đã gặp vấn đề sau trong một cuộc phỏng vấn (rằng tôi đã không giải quyết được, không cố gắng gian lận trong quá khứ): Trò chơi bắt đầu với số nguyên dương . (Ví dụ A 0 = 1234. ) Số này được chuyển đổi thành biểu diễn nhị phân và N là số bit được đặt thành 1 . (Ví dụ: A 0 = bA0A0=1234N1 , N = 5. )A0=b100 1101 0010N=5.

Người chơi 1 chọn số nhỏ hơn A 0 . B 0 chỉ có một bit được đặt thành 1. (Ví dụ: B 0 = b 10 0000 0000 = 512. ) Đặt A 1 = A 0 - B 0 . (Ví dụ: A 1 = 1234 - 512 = 722 = b 10 1101 0010. ) Di chuyển là hợp lệ nếu B 0B0A0B0B0=b10 0000 0000=512A1=A0B0A1=1234512=722=b1011010010B0đáp ứng những hạn chế trước đó, và nếu số lượng các bit đặt trong là vẫn tương đương với N .A1

Người chơi 2 tiếp tục từ bằng cách chọn B 1 hợp lệ , sau đó người chơi 1 tiếp tục từ A 2 , v.v. Một người chơi thua nếu họ không còn di chuyển hợp lệ.A1B1A2

Giả sử cả hai người chơi chơi tối ưu, xác định người chơi chiến thắng bằng phương pháp hợp lý hiệu quả. (Theo định nghĩa vấn đề của tôi, hạn chế của điều này là chương trình phải có khả năng cung cấp giải pháp cho một vài triệu số đầu vào phù hợp với số nguyên 32 bit đã ký.) Đó là, giải pháp không cần phải có phân tích đầy đủ.


Sở thích cá nhân của tôi ở đây là tìm hiểu xem liệu kỳ vọng của tôi có tìm ra và thực hiện giải pháp chính xác mà không có phản hồi nào về tính đúng đắn trong 120 phút tôi đưa ra là hợp lý hay không; hoặc nếu đây là một trong những câu hỏi "hãy xem họ đã xem câu đố này trước đây chưa".

Tôi đã thất bại vì tôi đã chọn thực hiện một chiến lược hợp lý, điều đó mang lại cho tôi kết quả chính xác cho một vài trường hợp thử nghiệm mà tôi đã từ bỏ, lãng phí quá nhiều thời gian để thực hiện nhanh chóng và kết thúc không chính xác đầu ra đầy đủ như thời gian của tôi đã hết.

Nhìn lại, tôi nên thực hiện một tìm kiếm mạnh mẽ và ghi nhớ các giải pháp từng phần cho các số bắt đầu nhỏ, nhưng nhận thức muộn luôn là 20/20. Tuy nhiên, tôi tò mò nếu có một cách tiếp cận phổ biến khác đã lảng tránh tôi như một kẻ lừa đảo.


Từ mô tả tôi đã không nắm bắt được rằng các bước di chuyển được chọn phải có một bit được đặt thành 1 (tôi nghĩ đó chỉ là một phần của ví dụ).
jjmontes

@jjmontes - Nó được tuyên bố là quy tắc đầu tiên để chọn số B - tất cả các ví dụ được chỉ định như vậy, mọi thứ bên ngoài dấu ngoặc đơn là chung. Bạn có một gợi ý làm thế nào nó có thể đã rõ ràng hơn?
millimoose

1
Có lẽ "Player 1 chọn một số ít hơn Một 0 , mà phải có chỉ có một bộ chút để 1."? (có lẽ đó chỉ là tôi, nhưng tôi đã phải đọc câu trả lời @orlp để nhận ra đây là một hạn chế). B0A0
jjmontes

@Veedrac - Man, tôi đã biết rằng, tất cả nỗ lực của tôi để làm cho bitcount chạy nhanh một cách hợp lý sẽ không lãng phí. Một câu trả lời giải thích tại sao nó hoạt động sẽ là tuyệt vời.
millimoose

@millimoose Bitcount có trong phần cứng cho hầu hết các CPU hiện đại!
Veedrac

Câu trả lời:


21

Hãy dành một chút thời gian cho bản thân bạn để nhận ra rằng nếu chúng ta chỉ có thể trừ đi sức mạnh của hai và số lượng người không thể thay đổi, chúng ta phải trừ đi ở vị trí mà số kia là 10 . Kết quả của điều đó luôn luôn là0110 ở vị trí đó và con số không thay đổi ở bất kỳ nơi nào khác.01

Nói cách khác, trò chơi là một chuỗi các giao dịch hoán đổi , và trò chơi kết thúc nếu tất cả những người ở phía bên tay phải. Lưu ý rằng trò chơi này không thể kết thúc sớm - bạn không thể gặp khó khăn. Bạn sẽ luôn kết thúc tại một vị trí mà tất cả các số 0 ở bên trái và tất cả các số ở bên phải.1001

Vì vậy, yếu tố quyết định duy nhất trong một trò chơi là cần bao nhiêu lần hoán đổi để đến trạng thái nơi tất cả những người ở bên phải, và không có chiến lược thắng hay thua. Tính chẵn lẻ của số lần hoán đổi là yếu tố quyết định duy nhất.

Vì vậy, có bao nhiêu giao dịch hoán đổi? Lưu ý rằng 1 giây không thể vượt qua nhau, vì vậy nếu chúng tôi đánh số chúng và theo dõi chúng thông qua các giao dịch hoán đổi thì chúng vẫn giữ nguyên thứ tự ở trạng thái cuối cùng. Mỗi trao đổi mang lại cho họ một gần hơn với vị trí cuối cùng của họ.

Vì vậy, nếu thứ 1 (đếm từ bên phải, ngoài cùng bên phải 10 lần thứ 1 ) là ở vị trí k từ cánh phải, nó cần k - i giao dịch hoán đổi để có được vị trí chính xác của nó. Điều này cung cấp cho chúng tôi một thuật toán để đếm số lượng giao dịch hoán đổi cần thiết:i1101kki

i = 0
k = 0
total = 0
while n > 0:
    if n & 1:
       total += k - i
       i += 1
    n >>= 1
    k += 1

Bây giờ chúng ta chỉ có thể nhìn vào sự tương đương totalđể xem ai là người chiến thắng. Độ phức tạp thời gian là .O(logn)


Điều này có vẻ đúng, tôi đã vấp phải các bit và phần của phương pháp này sau khi thực hiện. Đoán tôi đã hoàn thành bằng cách nhảy súng bắt đầu mã hóa và bị sa lầy trong cuộc rượt đuổi ngỗng hoang dã.
millimoose

Nghĩ về điều này, thực tế chiến lược không thành vấn đề có nghĩa là tôi có một lỗi khá mơ hồ trong quá trình triển khai của mình hoặc nó sẽ tạo ra kết quả tương tự như bất kỳ triển khai nào khác chơi trò chơi chính xác
millimoose vào

5

Một cách để giải quyết vấn đề như vậy là như sau:

  • Tìm giải pháp cho một vài giá trị đơn giản bằng cách sử dụng phương pháp "brute-force" được ghi nhớ mà bạn đang đề xuất.

  • Đoán câu trả lời (vị trí nào thắng và thua).

  • Hãy cố gắng chứng minh câu trả lời của bạn. Nếu bạn thành công, thật tuyệt. Nếu không, hãy thử tìm một ví dụ mẫu và sử dụng nó để đoán câu trả lời khác. Ở đây nó có thể hữu ích để giải quyết một vài trường hợp.

Thật sự rất khó để nói mất bao nhiêu thời gian. Tuy nhiên, trong các cuộc phỏng vấn bạn không nhất thiết phải tìm ra giải pháp. Thay vào đó, người phỏng vấn muốn biết cách bạn tiếp cận giải quyết vấn đề và tiến trình bạn đạt được.


Vâng không, họ đã từ chối tôi vì đầu ra của tôi sai và tôi đã hết thời gian.
millimoose

Cách tiếp cận vũ phu được ghi nhớ sẽ là chính xác, vì nó không có lối tắt nào liên quan đến chiến lược. Tuy nhiên, nó cũng vậy - tôi đã hiểu - chậm đến mức không thể chịu đựng được, và việc ghi nhớ có thể là quá nhiều công việc hàng đầu vì có thể không có nhiều sự giúp đỡ nếu không sử dụng số lượng bộ nhớ ngớ ngẩn. Hoặc có thể không, tôi sẽ thử sau đó chỉ để xóa cái này khỏi hệ thống của tôi.
millimoose

5

Lưu ý từ câu trả lời của @ orlp rằng chúng tôi muốn tính chẵn lẻ của tổng số các chuyển vị từ vị trí bắt đầu đến vị trí kết thúc. Hãy chú thích điều này:

       9876543210
       9 76 4  1    (positions at start)
start: 1011010010
end:   0000011111
            43210   (positions at end)

Vì vậy, chúng tôi muốn

  ((1 - 0) + (4 - 1) + (6 - 2) + (7 - 3) + (9 - 4)) & 1
= ((1 + 4 + 6 + 7 + 9) - (0 + 1 + 2 + 3 + 4)) & 1
= ((1 + 0 + 0 + 1 + 1) - (0 + 1 + 0 + 1 + 0)) & 1

Phần đầu tiên chỉ là tính chẵn lẻ của số bit trong các vị trí lẻ. Bạn có thể che dấu điều đó bằng cách lấy số nguyên không dấu tối đa, chia cho 0b11 và phủ định.

= (bitcount(x & ~(UINT_MAX / 0b11)) ^ (0 + 1 + 0 + 1 + 0)) & 1

Phần thứ hai là tính chẵn lẻ của một nửa số bit trong x.

= (bitcount(x & ~(UINT_MAX / 0b11)) ^ (bitcount(x) >> 1)) & 1

bitcountcó thể sử dụng popcnthướng dẫn phần cứng hoặc có thể được thực hiện bằng tay sử dụng chỉ cần bit cuối cùng hoặc từ giây đến cuối cùng, với mức giảm nhanh như thế này .

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.