กำหนดกราฟไม่มีทิศทาง มีน้ำหนัก n จุดยอด m เส้นขอบ คะแนนกราฟ = ผลรวมน้ำหนักขอบทั้งหมด น้ำหนักอาจเป็นลบ (ลบออกคะแนนจะเพิ่ม) ต้องลบขอบบางส่วนเพื่อทำให้คะแนนน้อยที่สุด (คือลดคะแนนมากที่สุด) แต่กราฟต้องยังคงเชื่อมต่อ ต้องการหาจำนวนคะแนนที่ลดได้สูงสุด
ตัวอย่าง: n=5,m=6, edges={{2,{1,2}},{2,{1,3}},{1,{2,3}},{3,{2,4}},{2,{2,5}},{1,{3,5}}} ผลลัพธ์: 4 (ลบขอบ (1,2) และ (2,5) น้ำหนักรวม 4 กราฟยังเชื่อมต่อ)
ขั้นตอนการแก้ปัญหา (Kruskal แบบปรับเปลี่ยน / Union-Find)
- Union-Find (
make, find, unify) นับคอมโพเนนต์cnum - เรียงขอบตามน้ำหนักน้อยไปมาก
- เริ่มต้น
make(i)ทุกจุดยอดcnum = n - วนขอบที่เรียงแล้ว:
- ถ้าจุดยอดอยู่คอมโพเนนต์เดียวกัน (
find(a)==find(b)) และน้ำหนัก ≥ 0 → บวกเข้าผลลัพธ์ (ลบขอบนี้ได้) - ถ้า
cnum == 1(เชื่อมต่อครบแล้ว) และน้ำหนัก ≥ 0 → บวกเข้าผลลัพธ์ - มิฉะนั้น
unify(a,b)(เก็บขอบนี้ไว้เพื่อความเชื่อมต่อ)
- ถ้าจุดยอดอยู่คอมโพเนนต์เดียวกัน (
- คืนค่าผลลัพธ์
ตัวอย่างโค้ด C++
#include <bits/stdc++.h>
using namespace std;
int cnum = 0, par[100], dim[100];
void make(int v) { par[v] = v; dim[v] = 1; }
int find(int v) { return par[v] == v ? v : par[v] = find(par[v]); }
void unify(int a, int b) {
a = find(a); b = find(b);
if (a != b) {
cnum--;
if (dim[a] > dim[b]) swap(a, b);
par[a] = b; dim[b] += dim[a];
}
}
int solve(int n, int m, vector<pair<int, pair<int,int>>> edges) {
cnum = n;
sort(edges.begin(), edges.end());
for (int i = 1; i <= n; i++) make(i);
int res = 0;
for (auto &edge : edges) {
int a = edge.second.first, b = edge.second.second, w = edge.first;
if (find(a) == find(b)) {
if (w >= 0) res += w;
continue;
}
if (cnum == 1) {
if (w >= 0) res += w;
} else unify(a, b);
}
return res;
}
int main() {
int n = 5, m = 6;
vector<pair<int, pair<int,int>>> edges = {{2,{1,2}},{2,{1,3}},{1,{2,3}},{3,{2,4}},{2,{2,5}},{1,{3,5}}};
cout << solve(n, m, edges);
return 0;
}
อินพุต / เอาต์พุต
Input: 5, 6, {{2,{1,2}},{2,{1,3}},{1,{2,3}},{3,{2,4}},{2,{2,5}},{1,{3,5}}}
Output: 4