Có giải pháp nào nhanh hơn cho vấn đề Great Wall Jam của Google Code không


16

Hãy xem xét câu hỏi Google Code Jam vòng 1C sau đây:

Vạn Lý Trường Thành của Trung Quốc bắt đầu như một đường thẳng vô tận, trong đó chiều cao ở tất cả các vị trí là .0

Một số bộ lạc , , sẽ tấn công vào tường theo các thông số sau - ngày bắt đầu, , cường độ bắt đầu , tọa độ hướng tây bắt đầu, và tọa độ hướng đông bắt đầu, . Tấn công đầu tiên này xảy ra vào ngày , trên phạm vi , ở sức mạnh . Nếu có bất kỳ phần nào của Vạn Lý Trường Thành trong có chiều cao , cuộc tấn công thành công và vào cuối ngày, bức tường sẽ được xây dựng sao cho bất kỳ đoạn nào của nó trong chiều cao sau đó sẽ ở chiều caoN 1000 D S W E D [ W , E ] S [ W , E ] < S [ W , E ] < S SNN1000DSWED[W,E]S[W,E]<S[W,E]<SS (hoặc lớn hơn, nếu một số cuộc tấn công khác vào ngày hôm đó đánh vào cùng phân khúc với sức mạnh )S'>S

Mỗi bộ lạc sẽ thực hiện tối đa cuộc tấn công trước khi rút lui và mỗi cuộc tấn công sẽ được xác định lặp đi lặp lại từ cuộc tấn công trước đó. Mỗi bộ lạc có một số , và xác định chuỗi tấn công của họ: Họ sẽ đợi ngày giữa các cuộc tấn công, họ sẽ di chuyển các đơn vị phạm vi tấn công cho mỗi cuộc tấn công ( = west, positive = đông), mặc dù kích thước của phạm vi sẽ giữ nguyên và sức mạnh của chúng cũng sẽ tăng / giảm theo một giá trị không đổi sau mỗi lần tấn công.δ D δ X δ S δ D1 δ X1000δDδXδSδD1δX

Mục tiêu của vấn đề là, được mô tả đầy đủ về các bộ lạc tấn công, xác định có bao nhiêu cuộc tấn công của họ sẽ thành công.

Tôi đã quản lý để mã hóa một giải pháp hoạt động được, chạy trong khoảng 20 giây: Tôi tin rằng giải pháp tôi đã triển khai mất thời gian , trong đó tổng số lần tấn công trong một mô phỏng (tối đa ) và tổng số điểm cạnh duy nhất trên phạm vi tấn công (tối đa ).Ôi(Mộtđăng nhậpMột+(Một+X)đăng nhậpX)Một= =1000000X= =2000000

Ở cấp độ cao, giải pháp của tôi:

  • Đọc tất cả thông tin của Bộ lạc
  • Tính toán tất cả các tọa độ duy nhất cho phạm vi tấn công -XÔi(Một)
  • Đại diện cho Tường dưới dạng cây nhị phân được cập nhật một cách lười biếng trên các phạm vi theo dõi các giá trị chiều cao tối thiểu. Một chiếc lá là khoảng của hai tọa độ không có gì ở giữa và tất cả các nút cha biểu thị khoảng thời gian liên tục được bao phủ bởi con cái của chúng. -XXÔi(Xđăng nhậpX)
  • Tạo tất cả các Tấn công mà mọi Bộ lạc sẽ thực hiện và sắp xếp chúng theo ngày -Ôi(Mộtđăng nhậpMột)
  • Đối với mỗi cuộc tấn công, hãy xem liệu nó có thành công không ( thời gian truy vấn). Khi ngày thay đổi, lặp qua tất cả các cuộc tấn công thành công chưa được xử lý và cập nhật tường phù hợp ( thời gian cập nhật cho mỗi cuộc tấn công). -đăng nhậpXđăng nhậpXÔi(Mộtđăng nhậpX)

Câu hỏi của tôi là: Có cách nào tốt hơn không? Có lẽ, có một số cách chiến lược để tận dụng bản chất tuyến tính của các cuộc tấn công liên tiếp của Tribes? 20 giây cảm thấy quá dài cho một giải pháp dự định (mặc dù Java có thể đổ lỗi cho điều đó).Ôi(Mộtđăng nhậpMột+(Một+X)đăng nhậpX)


3
Xin đừng đóng nó. Đó là một câu hỏi hợp lệ. Một câu trả lời sẽ là một bằng chứng ràng buộc thấp hơn, cho thấy chúng ta không thể làm tốt hơn, nếu đó thực sự là điều tốt nhất chúng ta có thể làm. Ví dụ, tôi đoán rằng chúng ta có thể sử dụng Vấn đề Phân biệt Yếu tố ở đây, nhưng chưa tìm thấy thời gian để suy nghĩ về nó.
Aryabhata

Tôi sẽ giữ cho nó mở :)
torquestomp

Câu trả lời:


2

Phòng rõ ràng để cải thiện là bước này:

Tạo ra tất cả các cuộc tấn công mỗi Tribe sẽ thực hiện, và sắp xếp chúng theo ngày - Ôi(Mộtđăng nhậpMột)

Chúng tôi biết rằng các bộ lạc sẽ tấn công từ một ngày cụ thể, trong khoảng thời gian đều đặn. Điều đó có nghĩa là về cơ bản chúng ta nên hợp nhất nhiều danh sách được sắp xếp trước. Ngoài ra, báo cáo vấn đề cho chúng ta biết rằng sẽ không bao giờ có hơn 1.000 bộ lạc (tức là 1.000 danh sách để hợp nhất); một con số nhỏ so với 1.000.000 cuộc tấn công tối đa! Tùy thuộc vào thời gian tương đối của việc triển khai của bạn, việc chuyển đổi này có thể giảm một nửa thời gian xử lý.

Đó thực sự là tất cả những gì tôi có thể đề xuất để tối ưu hóa sự phức tạp về mặt lý thuyết, nhưng tôi không có bằng chứng nào cho thấy nó sẽ tối ưu sau khi thay đổi này.


Tôi đã tự mình giải câu đố, nhưng tôi đã sử dụng một đại diện rất nhiều của bức tường: một cây tìm kiếm nhị phân ( std::mapchính xác là C ++ ) lưu trữ các vị trí nơi chiều cao của bức tường thay đổi. Với điều này, tôi có thể thêm và loại bỏ các nút theo yêu cầu (nghĩa là nếu một phần phức tạp phải chịu một cuộc tấn công lớn, áp đảo hoặc nhiều cuộc tấn công có cùng sức mạnh, số lượng nút sẽ giảm đáng kể). Điều này đã giải quyết đầu vào lớn trong 3,9 giây (trên máy tính xách tay phát triển mid-spec của tôi). Tôi nghi ngờ có một số lý do cho sự cải thiện:

  • Như bạn đã chỉ ra, quyền anh và unboxing có thể tốn kém, nhưng các thùng chứa dựa trên mẫu của C ++ tránh hoàn toàn điều này.
  • Mặc dù đại diện trên tường mà tôi sử dụng kém hơn về mặt lý thuyết, trong phần lớn các trường hợp có thể tự động giảm số lượng nút làm cho nó siêu nhanh (hầu hết các trường hợp kiểm tra tối đa ở mức dưới 1k nút, và tất cả trừ 2 đều dưới 10k) . Trong thực tế, trường hợp duy nhất mất bất kỳ thời gian đáng kể nào là # 7, dường như đã thử nghiệm rất nhiều phạm vi không giao nhau.
  • Tôi đã không sử dụng tiền xử lý (các giai đoạn được xác định bằng cách theo dõi thời điểm mỗi bộ lạc sẽ tấn công tiếp theo và tìm kiếm điểm thấp nhất mỗi lượt). Một lần nữa, điều này về mặt lý thuyết tồi tệ hơn, nhưng đối với phần lớn các trường hợp tôi nghi ngờ chi phí thấp hơn có nghĩa là nó nhanh hơn (tôi sẽ kiểm tra điều này và lấy lại cho bạn). Cập nhật : Tôi đã thêm một hàng đợi ưu tiên cho các cuộc tấn công, tương tự như phương pháp được mô tả ở trên (mặc dù thay vì tạo mảng lớn tôi đã tính toán khi đang di chuyển) và thấy thời gian giảm xuống còn 3.0 giây cho đầu vào lớn.

Nói tóm lại, trong khi tôi nghĩ thuật toán của bạn gần như tối ưu trong trường hợp chung, có một số cách bạn có thể tăng tốc cho các đầu vào thông thường .


1

Sau đây đã được gỡ bỏ khỏi câu hỏi, vì nó là một câu trả lời.

Nhìn qua các cuộc thảo luận khác và các giải pháp thành công dường như chỉ ra rằng giải pháp mà tôi đã mô tả gần như là thuật toán dự kiến. Sự chậm lại trong giải pháp của tôi có lẽ chỉ là do lười sử dụng tự động đấm bốc và cấu trúc cây dựa trên con trỏ, chứ không phải là cấu trúc dựa trên mảng - vì vậy tôi nghi ngờ rằng, nếu một giải pháp tồn tại, có lẽ nó không phải là toàn bộ tốt hơn nhiều so với những gì ở đây.

Các giải pháp có thể được tìm thấy ở đây . Nó rất giống với những gì tôi đã đăng ở đây; vì vậy tôi có xu hướng tin rằng một giải pháp hiệu quả hơn không tồn tại.

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.