เรามีลูกค้าจะซื้อกระเป๋า คน ไล่คิวจากคนที่ ถึงคนที่ โดยคนที่ สามารถเดินได้ไกลสุด ตำแหน่งได้ โดย:
เขียนโค้ดที่จะคำนวณจำนวนครั้งที่พนักงานต้องจัดวางกระเป๋าใหม่ให้น้อยที่สุด
เราจะพยายามวางกระเป๋าของลูกค้าคนที่ ให้อยู่ไกลที่สุดที่เป็นไปได้ เพื่อจะได้มีพื้นที่ด้านหน้าให้กับลูกค้าคนอื่นที่ มีค่าน้อยๆ
วิธีการเขียนแบบ Brute Force คือ เราจะมี array ที่จะเก็บว่า ชั้นวางที่ ได้วางกระเป๋าไว้หรือยัง (ตอนเริ่มต้น สำหรับทุกๆ ) โดยเราจะเริ่ม loop จาก slot ที่ ไปจนถึง แล้วถ้าหากว่าช่องที่เรากำลังตรวจสอบอยู่ยังไม่ได้วางกระเป๋าไว้ () เราจะ mark ช่องนั้นว่าถูกใช้แล้ว () และถ้าหากว่าเรา loop จาก ถึง แล้วไม่มีช่องใดที่ว่างเลย แสดงว่า ทุกๆช่องที่ลูกค้าคนนี้สามารถเดินไปได้ ไม่มีช่องไหนว่างเลย เราจะ reset array โดยตั้งให้ทุกช่องเป็น และก็คำนวณเหมือนเดิมจนครบ คน
ปัญหาของการเขียนวิธีนี้คือ time complexity ในกรณีที่แย่ที่สุด จะเป็น ซึ่งยังไงก็จะโดน TLE แน่ๆ
ดังนั้น ความยากของโจทย์ข้อนี้คือ วิธีการที่เราจะ optimize โค้ดให้เหลือ โดยเราจะใช้ DSU (Disjoint Set Union) ในการ optimize โค้ดข้อนี้
เราจะ loop แต่ละคนจาก ถึง เหมือนเดิม แต่แทนที่จะคำนวณตรงๆ ทุกๆรอบที่เราคำนวณ เราจะให้ root ของค่า แทนเป็น slot แรกที่เราจะสามารถวางกระเป๋าให้ลูกค้าที่สามารถเดินไปได้มากสุด ชั้นวาง ซึ่งตอนเริ่มต้นเราจะตั้งให้ มีค่าเป็น ทุกช่อง และทุกๆรอบที่เรา loop เราจะหาว่า ช่องแรกที่เราสามารถวางกระเป๋าให้คนที่ คือช่องที่เท่าไหร่ (หา root ของ ) แล้วทีนี้ จะมีอยู่ 2 กรณี ได้แก่:
เราไม่สามารถ reset array ได้ เพราะว่า time complexity ที่เราต้องใช้ในการ reset array จะเท่ากับ
เราจะเก็บ auxiliary array ซึ่งจะเก็บว่า ชั้นวางที่ เราจะวางกระเป๋าของลูกค้าคนที่เท่าไหร่ และเราจะเก็บตัวแปรเพิ่ม 1 ตัวเป็น integer ชื่อว่า (ย่อจาก first) โดย จะเก็บว่า สำหรับการจัดกระเป๋ารอบนี้ ลูกค้าคนแรกที่เราจัดกระเป๋าให้คือลูกค้าคนที่เท่าไหร่ โดยตอนที่เราหา root ของ เราจะเช็กใน auxiliary array นั้นก่อนว่า กระเป๋าที่เราจะวางในชั้นวางที่ นั้น เป็นกระเป๋าของใคร ถ้าหากว่าเป็นกระเป๋าของลูกค้าที่หมายเลขน้อยกว่า ก็แสดงว่า เราไม่ต้องสนใจลูกค้าคนนั้นแล้ว เพราะว่า ลูกค้าคนนั้นได้รับกระเป๋าไปแล้ว และเรากำลังจะจัดกระเป๋าบนชั้นวางใหม่อีกรอบ ซึ่งจะทำให้ time complexity ทั้งหมด ลดเหลือ นั่นเอง
#include <bits/stdc++.h>
using namespace std;
const int N = 2e6 + 5;
int i, f, aux[N], par[N];
int dsu(int x){
if (aux[x] < f) {
aux[x] = i;
par[x] = x;
}
return par[x] = (par[x] == x ? x : dsu(par[x]));
}
int minimum_bag_rearrangement_time(vector <int> max_allowed_positions){
int n = max_allowed_positions.size(); f = 1;
iota(par, par + N, 0);
memset(aux, -1, sizeof aux);
int ans = 0;
for (i = 1; i <= n; i++) {
int x = dsu(max_allowed_positions[i - 1]);
if (x <= 0) {
ans++, f = i;
x = dsu(max_allowed_positions[i - 1]);
}
par[x] = dsu(x - 1);
}
return ans;
}
หากมีข้อสงสัย comment ไว้ใต้ post ได้เลยนะครับ 🙇♂️🙇♂️
ศึกษาโจทย์เพิ่มเติมได้ที่ Fast X Fourier