Skip to content

Edit o59_may03_signal #187

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 63 additions & 7 deletions md/o59_may03_signal.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,69 @@
ในข้อนี้เราเขียนระยะห่างระหว่าง access point $i$ และ access point $j$ ด้วย $d(i, j)$ ซึ่งเราจะนิยามให้ $d(i, j) = (x_i-x_j)^2 + (y_i-y_j)^2$
เราจะเขียนระยะห่างกำลังสองระหว่าง access point $i$ และ access point $j$ ด้วย $d(i, j)$ ซึ่งโดยนิยาม $d(i, j) = (x_i-x_j)^2 + (y_i-y_j)^2$

สมมติก่อนว่าเรารู้ค่า $P$ แล้ว ค่า $a[i][j]$ ซึ่งบอกว่า access point $i$ คุยกับ access point $j$ ได้ไหม ควรจะมีค่าเป็น $1$ ก็ต่อเมื่อ $d(i, j) \leq P^2$ เท่านั้น มิเช่นนั้นควรจะมีค่าเป็น $0$
สมมติก่อนว่าเรารู้ค่า $P$ แล้ว กำหนดให้ $b[i][j]$ บอกว่า access point $i$ คุยกับ access point $j$ ได้ไหม เรารู้ว่า $b[i][j]$ ควรจะมีค่าเป็น $1$ ก็ต่อเมื่อ $d(i, j) \leq P^2$ มิเช่นนั้นควรจะมีค่าเป็น $0$

หากเรานำค่า $a[i][j]$ **จริง**ทั้งหมดมาเรียงกันจากน้อยไปมากตามค่า $d(i, j)$ ที่เกี่ยวข้องกับมัน จะได้ลำดับใหม่คือ $S_1, S_2, S_3, ..., S_m$ ($m =$ จำนวนข้อมูล) เราจะได้ว่า จะมี index $k$ โดย $0 \leq k \leq m$ ที่ $S_i = 1$ สำหรับ $1 \leq i \leq k$ และ $S_i = 0$ สำหรับ $k< i \leq m$ กล่าวคือลำดับจะเป็นเลข $1$ ตลอดไปจนถึงจุด ๆ หนึ่ง แล้วเปลี่ยนเป็น $0$ ตลอดจนจบลำดับ (หรืออาจจะไม่มี $1$ เลยก็ได้)
หากเรานำเส้นเชื่อมทั้งหมดระหว่าง access point สองตัวใด ๆ มาเรียงกันจากน้อยไปมากตามค่า $d(i, j)$ จะได้ลำดับของเส้นเชื่อมคือ $E_1, E_2, E_3, ..., E_m$ (โดย $m = n^2$ ซึ่งคือจำนวนเส้นเชื่อม) ให้ $b[E_k]$ แทน $b[i][j]$ สำหรับ $i, j$ ที่สัมพันธ์กับเส้นเชื่อม $E_k$ เราจะทราบว่าลำดับ $b[E_1], \dots, b[E_m]$ จะเป็น $1$ ตลอดไปจนถึงจุด ๆ หนึ่ง แล้วเปลี่ยนเป็น $0$ ตลอดจนจบลำดับ (หรืออาจจะไม่มี $0$ เลยก็ได้) หรือสามารถเขียนเป็นคณิตศาสตร์ได้ว่า จะมี index $k$ ที่ทำให้ $b[E_i] = 1$ สำหรับทุก $1 \leq i \leq k$ และ $b[E_i] = 0$ สำหรับทุก $k < i \leq m$

ดังนั้นเพื่อที่จะหาคำตอบที่ดีที่สุด เราจะสร้างลำดับ $T$ โดยวิธีคล้ายกับการสร้างลำดับ $S$ ข้างต้น แต่เราจะใช้ค่า $a[i][j]$ **ที่โจทย์ให้มา**แทน จากนั้นเราจะไล่เทียบกับ $S$ ที่เป็นไปได้ทั้งหมดโดยการเปลี่ยนค่า $k$ ไปเรื่อย ๆ จาก $k=0$ ถึง $k=m$ (ซึ่ง $k$ คือจุดสุดท้ายที่ลำดับ $S$ มีค่าเป็น $1$) แล้วในแต่ละครั้งของการไล่ เราจะคำนวณหาจำนวนสมาชิกของ $T$ ที่ไม่เหมือน $S$ คำตอบของเราจะมีค่าเท่ากับค่าที่น้อยที่สุดของจำนวนที่สมาชิกที่ต่างกันในแต่ละครั้งของการไล่
ดังนั้นเพื่อที่จะหาคำตอบที่ดีที่สุด เราจะสร้างลำดับโดยวิธีคล้ายกับการสร้างลำดับ $b[E_i]$ ข้างต้น แต่เราจะใช้ค่า $a[i][j]$ ที่โจทย์ให้มาแทน นั่นคือจะได้ลำดับ $a[E_i]$

แต่ข้อนี้มีข้อควรระวังคือ เราจะไม่สามารถใช้ $k$ บางค่าได้ เนื่องจากอาจจะมีกรณีที่ระยะทางมีค่าเท่ากัน ยกตัวอย่างเช่น ลำดับ $T$ ของเราอาจจะมีค่า $d(i, j)$ ที่สอดคล้องเท่ากับ $10, 25, 30, 30, 30, 45, 60$ สังเกตว่าถ้าเราให้ $k = 3$ จะได้ว่า $30 \leq P^2$ และ $30 > P^2$ ในเวลาเดียวกัน ซึ่งไม่สามารถเป็นไปได้ ดังนั้นเวลาไล่ค่า $k$ ให้เราข้าม index พวกนี้ไปเลย
จากนั้นเราจะหาว่าลำดับ $a[E_i]$ ที่เราได้มา ใกล้เคียงกับการเป็นลำดับ $b[E_i]$ มากแค่ไหน พูดอีกอย่างคือการหาว่าเราต้องสลับ $1$ กับ $0$ อย่างน้อยกี่ตัวที่จะทำให้ลำดับ $a[E_i]$ เป็นลำดับที่เริ่มจาก $1$ ตลอดไปจนถึงจุด ๆ หนึ่ง แล้วเปลี่ยนเป็น $0$ ตลอดจนจบลำดับ (หรืออาจจะไม่มี $0$ เลยก็ได้)

ในการคำนวณหาจำนวนสมาชิกที่ต่าง ให้เราเก็บจำนวนของ $0$ จนถึงตำแหน่ง $k$ เพื่อใช้ในการคำนวณคำตอบ จากนี้ เราสามารถคำนวณจำนวนของ $1$ หลังตำแหน่ง $k$ ได้ด้วย ดังนั้นเราก็จะสามารถคำนวณคำตอบในแต่ละครั้งของการเปลี่ยนค่า $k$ ได้เร็ว ๆ
เราทำได้โดยการไล่เทียบกับ $b[E_i]$ ที่เป็นไปได้ทั้งหมดโดยการเปลี่ยนค่า $k$ ไปเรื่อย ๆ จาก $k=0$ ถึง $k=m$ (ซึ่ง $k$ คือจุดสุดท้ายที่ลำดับ $b[E_i]$ มีค่าเป็น $1$ ทุกตัว) แล้วในแต่ละครั้งของการไล่ เราจะคำนวณหาจำนวนสมาชิกของ $a[E_i]$ ที่ไม่เหมือน $b[E_i]$ คำตอบของเราจะมีค่าเท่ากับค่าที่น้อยที่สุดของจำนวนที่สมาชิกที่ต่างกันในแต่ละครั้งของการไล่

time complexity ของวิธีนี้จะเท่ากับ $\mathcal{O}(n^2 \log n)$ จากการ sort ลำดับ $T$ ซึ่งมีความยาวเท่ากับ $m = n^2$
แต่ข้อนี้มีข้อควรระวังคือ เราจะไม่สามารถใช้ $k$ บางค่าได้ เนื่องจากอาจจะมีกรณีที่ระยะทางมีค่าเท่ากัน ยกตัวอย่างเช่น ลำดับของเราอาจจะมีค่า $d(i, j)$ ที่สอดคล้องเท่ากับ $10, 25, 30, 30, 30, 45, 60$ สังเกตว่าถ้าเราให้ $k = 3$ จะได้ว่า $30 \leq P^2$ และ $30 > P^2$ ในเวลาเดียวกัน ซึ่งไม่สามารถเป็นไปได้ ดังนั้นเวลาไล่ค่า $k$ ให้เราข้าม index พวกนี้ไปเลย

ในการคำนวณหาจำนวนสมาชิกที่ต่าง ให้เราเก็บจำนวนของ $1$ จนถึงตำแหน่ง $k$ เพื่อใช้ในการคำนวณคำตอบ เราสามารถคำนวณจำนวนของ $0$ หลังตำแหน่ง $k$ ได้ด้วย ดังนั้นเราก็จะสามารถคำนวณคำตอบในแต่ละครั้งของการเปลี่ยนค่า $k$ ได้เร็ว ๆ การเปรียบเทียบนี้ควรทำได้ใน $\mathcal{O}(n^2)$

time complexity ของวิธีนี้จะเท่ากับ $\mathcal{O}(n^2 \log n)$ จากการ sort ลำดับซึ่งมีความยาวเท่ากับ $m = n^2$

```cpp
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second

pair<int, int> p[200];

struct Edge {
int i, j, d, a;
bool operator < (const Edge & o) const {
return d < o.d;
}
};

vector<Edge> v;
vector<int> qs;

int main(){
ios_base::sync_with_stdio(false); cin.tie(NULL);
int n; cin >> n;

for (int i = 1; i <= n; i++) cin >> p[i].x >> p[i].y;

for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
int report; cin >> report;
int dis = (p[i].x-p[j].x)*(p[i].x-p[j].x)
+ (p[i].y-p[j].y)*(p[i].y-p[j].y);
v.push_back({i, j, dis, report});
}
}

sort(v.begin(), v.end());
int n2 = v.size();
qs.resize(n2);

qs[0] = v[0].a;
for (int i = 1; i < n2; i ++) qs[i] = qs[i-1] + v[i].a;

int mn = 1e9;
for (int i = 0; i < n2; i ++) {
if (v[i].d == v[i+1].d) continue;
int error = (i+1 - qs[i]) + (qs[n2-1] - qs[i]);
mn = min(mn, error);
}
cout << mn;

return 0;
}
```