Lịch sử
Công ty của tôi gửi một bản tin hàng tuần cho mọi người trong công ty. Bao gồm trong các bản tin này là một câu đố, cùng với một tiếng hét cho bất cứ ai trong công ty là người đầu tiên gửi email / cung cấp một giải pháp cho câu đố tuần trước. Hầu hết các câu đố này khá tầm thường, và thực sự khá buồn tẻ đối với một công ty công nghệ, nhưng có một, vài tháng trước, điều đó đã thu hút sự chú ý của tôi.
Câu đố gốc:
Cho hình dưới đây:
Bạn có các số tự nhiên từ 1 đến 16. Ghép tất cả chúng vào hình dạng này, sao cho tất cả các hàng liền kề và các cột liền kề có tổng số lên tới 29.
Ví dụ, một giải pháp như vậy cho câu đố này (đó là giải pháp "kinh điển" mà tôi đã gửi đến bản tin) là:
Tuy nhiên, trong quá trình giải quyết nó, tôi đã tìm thấy một số thông tin khá thú vị:
- Có nhiều giải pháp hơn đáng kể so với chỉ có một; Trên thực tế, có 9.368 Giải pháp.
- Nếu bạn mở rộng quy tắc để chỉ yêu cầu các hàng và cột bằng nhau, không nhất thiết phải là 29, bạn sẽ nhận được 33.608 giải pháp:
- 4.440 Giải pháp cho tổng số 27.
- 7.400 Giải pháp cho tổng số 28.
- 9.368 Giải pháp cho tổng số 29.
- 6.096 Giải pháp cho tổng số 30.
- 5.1104 Giải pháp cho tổng số 31.
- 1.200 Giải pháp cho tổng số 32.
Vì vậy, tôi và đồng nghiệp của tôi (mặc dù hầu hết chỉ là người quản lý của tôi, vì anh ta là người duy nhất ngoài tôi có kỹ năng lập trình "Mục đích chung") đã đặt ra một thách thức, kéo dài trong hầu hết các tháng mà chúng tôi có, công việc thực tế khác- nghĩa vụ liên quan, chúng tôi đã phải tham dự vào chương trình cố gắng để viết một chương trình tìm mọi giải pháp một cách nhanh nhất có thể.
Thống kê gốc
Chương trình đầu tiên tôi viết để giải quyết vấn đề chỉ đơn giản là kiểm tra các giải pháp ngẫu nhiên lặp đi lặp lại và dừng lại khi tìm thấy giải pháp. Nếu bạn đã thực hiện phân tích toán học về vấn đề này, có lẽ bạn đã biết rằng điều này không nên làm việc; nhưng bằng cách nào đó tôi đã gặp may, và chương trình chỉ mất một phút để tìm ra một giải pháp duy nhất (giải pháp tôi đã đăng ở trên). Các lần chạy lặp lại của chương trình thường mất tới 10 hoặc 20 phút, vì vậy rõ ràng đây không phải là một giải pháp nghiêm ngặt cho vấn đề.
Tôi đã chuyển sang một Giải pháp đệ quy lặp đi lặp lại qua mọi hoán vị có thể có của câu đố và loại bỏ rất nhiều giải pháp cùng một lúc bằng cách loại bỏ các khoản tiền không cộng dồn. IE nếu hàng / cột đầu tiên tôi so sánh đã không bằng nhau, tôi có thể dừng kiểm tra nhánh đó ngay lập tức, biết rằng không có gì khác thấm vào câu đố sẽ thay đổi điều đó.
Sử dụng thuật toán này, tôi đã có được thành công "đúng đắn" đầu tiên: chương trình có thể tạo và phun ra tất cả 33.608 giải pháp trong khoảng 5 phút.
Người quản lý của tôi đã có một cách tiếp cận khác: dựa trên công việc của tôi rằng các giải pháp khả thi duy nhất có tổng số 27, 28, 29, 30, 31 hoặc 32, ông đã viết một giải pháp đa luồng chỉ kiểm tra các khoản tiền có thể có cho các giá trị cụ thể đó. Anh quản lý để có được chương trình của mình để chạy chỉ trong 2 phút. Vì vậy, tôi lặp lại một lần nữa; Tôi đã băm tất cả các khoản tiền 3/4 chữ số có thể (khi bắt đầu chương trình; nó được tính trong tổng thời gian chạy) và sử dụng "tổng một phần" của một hàng để tra cứu giá trị còn lại dựa trên một hàng đã hoàn thành trước đó, thay vì kiểm tra tất cả các giá trị còn lại và giảm thời gian xuống còn 72 giây. Sau đó, với một số logic đa luồng, tôi đã giảm xuống còn 40 giây. Người quản lý của tôi đã mang chương trình về nhà, thực hiện một số tối ưu hóa về cách chương trình chạy và giảm xuống còn 12 giây. Tôi sắp xếp lại việc đánh giá các hàng và cột,
Người nhanh nhất trong chúng tôi nhận được các chương trình của mình sau một tháng là 0,15 giây cho người quản lý của tôi và 0,33 giây cho tôi. Cuối cùng tôi đã tuyên bố rằng chương trình của tôi nhanh hơn, vì chương trình của người quản lý của tôi, trong khi nó đã tìm thấy tất cả các giải pháp, đã không in chúng ra thành một tệp văn bản. Nếu anh ta thêm logic đó vào mã của mình, nó thường mất tới 0,4-0,5 giây.
Kể từ đó, chúng tôi đã cho phép thử thách nội bộ của mình tồn tại, nhưng tất nhiên, câu hỏi vẫn là: có thể chương trình này được thực hiện nhanh hơn không?
Đó là thử thách tôi sẽ đặt ra cho các bạn.
Thử thách của bạn
Các tham số mà chúng tôi đã làm việc theo quy tắc "tổng 29" thay vào đó là "tổng của tất cả các hàng / cột" và tôi cũng sẽ đặt quy tắc đó cho các bạn. Do đó, Thách thức là: Viết chương trình tìm (và In!) Tất cả các giải pháp cho câu đố này trong thời gian ngắn nhất có thể. Tôi sẽ đặt trần cho các giải pháp đã gửi: Nếu chương trình mất hơn 10 giây trên một máy tính tương đối tốt (<8 tuổi), có lẽ quá chậm để tính.
Ngoài ra, tôi có một vài Phần thưởng cho câu đố:
- Bạn có thể khái quát hóa giải pháp để nó hoạt động cho bất kỳ bộ 16 số nào không, không chỉ
int[1,16]
? Điểm thời gian sẽ được đánh giá dựa trên bộ số nhắc nhở ban đầu, nhưng được chuyển qua bộ mã này. (-10%) - Bạn có thể viết mã theo cách mà nó xử lý một cách duyên dáng và giải quyết với các số trùng lặp không? Điều này không đơn giản như nó có vẻ! Các giải pháp "giống hệt trực quan" phải là duy nhất trong tập kết quả. (-5%)
- Bạn có thể xử lý số âm? (-5%)
Bạn cũng có thể thử tạo một giải pháp xử lý Số dấu phẩy động, nhưng tất nhiên, đừng bị sốc nếu thất bại hoàn toàn. Nếu bạn tìm thấy một giải pháp mạnh mẽ, đó có thể là một phần thưởng lớn!
Đối với tất cả ý định và mục đích, "Xoay vòng" được coi là giải pháp duy nhất. Vì vậy, một giải pháp chỉ là một vòng quay của một giải pháp khác được tính là giải pháp của chính nó.
Các IDE tôi đã làm việc trên máy tính của mình là Java và C ++. Tôi có thể chấp nhận câu trả lời từ các ngôn ngữ khác, nhưng bạn cũng có thể cần cung cấp một liên kết đến nơi tôi có thể có được môi trường thời gian chạy dễ cài đặt cho mã của bạn.