cf1245 D. Shichikuji and Power Grid(最小生成樹)
阿新 • • 發佈:2021-12-22
題意:
每個點用座標表示,在第 \(i\) 個點建電站的花費為 \(c_i\),在兩點 \(i,j\) 之間拉電線的代價為 \((k_i+k_j)d\) ,\(d\) 為曼哈頓距離。要求每個點要麼有電站,要麼與一個有點站的點連通,求最小花費並輸出一種方案。
思路:
建立超級源點0,0號點到每個點都連一條邊,權值為每個點建電站的花費。然後跑一遍prim,思路和Dijkstra一樣:維護last陣列記錄每個點最後被哪個點更新,在v[x]=1時更新答案。
#include <bits/stdc++.h> using namespace std; using ll = long long; const int N = 2005; int n, x[N], y[N], c[N], k[N]; ll dist(int i, int j) //計算邊權 { //if(i == j) return 0; if(i == 0) return c[j]; if(j == 0) return c[i]; return (ll)(k[i] + k[j]) * (abs(x[i]-x[j]) + abs(y[i]-y[j])); } ll d[N]; bool v[N]; int last[N]; vector<int> dian; vector<pair<int, int>> bian; ll ans; void prim() { memset(d, 0x3f, sizeof d), memset(v, 0, sizeof v); d[0] = 0; for(int i = 0; i <= n; i++) { int x = -1; for(int j = 0; j <= n; j++) if(!v[j] && (x == -1 || d[j] < d[x])) x = j; v[x] = 1; if(x > 0) { ans += d[x]; if(last[x] > 0) bian.push_back({x, last[x]}); //拉電線 else dian.push_back(x); //建電站 } for(int y = 0; y <= n; y++) if(!v[y]) if(d[y] > dist(x, y)) d[y] = dist(x, y), last[y] = x; } } signed main() { scanf("%d", &n); for(int i = 1; i <= n; i++) scanf("%d%d", &x[i], &y[i]); for(int i = 1; i <= n; i++) scanf("%d", &c[i]); for(int i = 1; i <= n; i++) scanf("%d", &k[i]); prim(); printf("%lld\n%d\n", ans, dian.size()); for(int i : dian) printf("%d ", i); printf("\n%d\n", bian.size()); for(auto i : bian) printf("%d %d\n", i.first, i.second); return 0; }