Tutorial
, DP-Bitmask
Chào mọi người, mình là thành viên của nhóm Editorial Slayers. Mình chia sẻ bài viết này như một cp blog bình thường nên là mong mọi người đừng ném đá nhé :D
//btw mục đích của bài viết cũng là để note lại và chia sẻ. Lưu ý rằng bài viết này không dành cho những bạn chưa biết đến quy hoạch động trạng thái (dp state). Mình khuyên các bạn nên skip nếu chưa từng nghe đến khái niệm trên, cơ mà nếu thích thì các bạn vẫn cứ đọc thôi :P
Cách đây vài hôm, trong lúc đang làm bài thì mình đã gặp một dạng bài dp trạng thái có cách đặt state rất hay. Cách đặt dp kiểu như vậy khi mới học dp state mình đã gặp một lần trong lúc đọc editorial của một anh nào đó mình không nhớ rõ vì cách đây cũng khá lâu rồi. Chia sẻ thêm là lúc đấy dp state cơ bản mình cũng chưa nắm rõ nên đọc solution của người viết mình cũng mập mờ và không hiểu mô tê gì hết :/
Thế cho nên là khi gặp lại dạng này, mình không nhận ra được và đã TLE sml. Tuyệt vọng vì tưởng máy chấm vnoj yếu (mà thật ra là do thuật mình chưa đúng chứ máy chấm vnoj yếu thật mà) thì mình quyết định nhá qua sol, sượt qua hình minh họa, mình nhận ra ngay rằng đã gặp kiểu dp này trong quá khứ rồi (nói quá khứ thì nghe hơi xưa nhỉ :/). Và mình cảm thấy rất phấn khích đến mức muốn note lại ngay cái mình vừa nhớ ra lúc đó.
Cụ thể là bài tập này trên vnoj
Tóm tắt :
Cho một bảng gồm hàng cột ( 1000, 10), mỗi ô trên bảng là một kí tự #
hoặc tương ứng cho ô đang mở và ô đang đóng. Bạn được cho một cuộn băng dính dài vô tận, và nó có chiều rộng bằng một ô trên bảng. Bạn có thể xé một đoạn băng dính và dùng nó để dán một đoạn liền kề những ô cửa sổ đã đóng theo chiều dọc hoặc chiều ngang. Hỏi số đoạn cần dùng ít nhất là bao nhiêu.
Chà, chắc bạn đang nghĩ bài này khá dễ, vì bé nên chỉ cần gọi
số cách tối ưu khi dán đến hàng và các trạng thái băng dính trên hàng là , với là các bit . biểu diễn cho ô dán băng dính ngang hoặc ô đang đóng, biểu diễn cho ô dán băng dính dọc. Chuyển trạng thái thì chỉ cần viết thêm 1 hàm tính chi phí cho 2 cái đang xét là xong.
Cơ mà đánh giá đpt thì tầm
với là số trạng thái, là chi phí chuyển + chi phí tính của 2 mỗi lần chuyển trạng thái. Nhìn thì có vẻ không AC. Tuy nhiên mình thử prune tí nhé (ý là xem xem có gì có thể bỏ qua để tối ưu không ý mà).
Với mỗi hàng, không hẳn số trạng thái của nó sẽ là vì có thể có sự xuất hiện của các ô , mình thử dùng 1 vector để lưu lại các trạng thái này và chỉ duyệt các trạng thái có trên các vector này thôi.
Thêm cái nữa là nhận thấy khi chuyển từ thì nó chỉ bị tăng lên 1 lượng không quá , (bạn có ô mỗi hàng, giờ tối đa là miếng băng dính nên lượng tăng lên cũng không quá ). Gọi là giá trị nhỏ nhất của các , mình sẽ pop ra hết trong vector lưu trạng thái đã được đề cập ở trên thằng nào có . Nghe có vẻ hợp lí rồi đấy, chắc đây là thứ người ra đề muốn mình làm, test thử thôi!
"Sặc, TLE sml rồi, prune như thế cũng không được nốt. Hmmm…"
Đánh giá lại cách làm trên, trong trường hợp xấu nhất là các ô đều là thì cách prune trên cũng không mang lại được gì trừ trường hợp người ra đề muốn mình làm thế, cho nên chắc hẳn sol chuẩn phải là một cái gì đó khác.
Sau một hồi lâu suy nghĩ thì mình đã chịu thua, vì ngoài cách dp như trên, mình không còn nghĩ ra được gì khác, đã đến lúc để đọc sol:v
Mình vửa mở sol lên, lướt xuống thì thấy hình ảnh này hiện lên
"aduuuuuuuuu"
Đó là cảm giác của mình lúc đấy, mình đã nhận ra cách đặt state dp cho bài này. Cảm thấy nó thật ảo diệu vì lâu rồi mình mới gặp lại nó (mà nó đã ảo diệu từ đầu rồi).
Cụ thể, bạn gọi là cách tối ưu khi xét đến hàng thứ , từ bit đến bit biểu diễn trạng thái của hàng thứ tại các cột . Các bit biểu diễn trạng thái của hàng tại các cột (do làm trên bit index từ , nên số cột mình cũng index từ luôn cho nó dễ). Để cho dễ hình dung, trên hình ô màu đỏ là ô ta đang xét, các ô xanh dương sẽ là các bit trong của chúng ta (tất nhiên là bao gồm cả ô màu đỏ).
wait, dừng khoảng chừng là 2s, tại sao lại có cách đặt trạng thái lạ thế?
Đơn giản là vì nó sẽ chuyển trạng thái được trong , yep, mình không đùa đâu, chúng ta có trạng thái và chúng ta chuyển trong . Và cũng chính vì cách đặt state rất lạ này mà nó khiến mình cảm thấy rất thích thú, ảo ma thật đấy :D.
Rồi giờ chuyển state như thế nào, nói ra khá dài dòng nên mình sẽ để các bạn đọc code rồi rút ra kết luận nhé :P
code của mình trông rất xấu và dài dòng, tất nhiên là có cách code ngắn gọn hơn rất nhiều bằng cách dùng vector và loại bỏ luôn 1 chiều của trạng thái, cách này code rất gọn
Time:
Space:
Đấy là những gì mình học được từ cách dp trên, đến đây là hết rồi, nếu bạn thấy bài viết này hay thì hãy nhớ theo dõi nhóm Editorial Slayers tụi mình để đón chờ những bài viết khác nữa nhé, chúc các bạn có một ngày học tập và làm việc thật tốt.