题意:(来源洛谷)
思路:一个非常巧妙的方法,将在城市i建造发电站看作是将城市i与城市0连接,代价即为ci。其他城市间则按题意建立边,求一次最小生成树即可。需要开long long。
代码:

1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const ll N = 2020; 5 struct edge{ 6 ll u, v, w; 7 edge(ll a, ll b, ll c): u(a), v(b), w(c) {} 8 bool operator < (const edge &x) const { 9 return w < x.w; 10 } 11 }; 12 ll k[N], cost[N], x[N], y[N], f[N]; 13 ll n; 14 vector <edge> e; 15 ll find(ll x) { 16 return x == f[x] ? x : f[x] = find(f[x]); 17 } 18 19 int main() 20 { 21 scanf("%lld", &n); 22 for (ll i = 1; i <= n; i++) 23 scanf("%lld %lld", &x[i], &y[i]); 24 for (ll i = 1; i <= n; i++) scanf("%lld", &cost[i]); 25 for (ll i = 1; i <= n; i++) scanf("%lld", &k[i]); 26 27 for (ll i = 1; i <= n; i++) e.push_back(edge(0, i, cost[i])); 28 for (ll i = 1; i <= n; i++) 29 for (ll j = 1; j <= n; j++) { 30 if (j <= i) continue; 31 e.push_back(edge(i, j, (k[i]+k[j])*(abs(x[i]-x[j])+abs(y[i]-y[j])))); 32 } 33 sort(e.begin(), e.end()); 34 vector <ll> a; 35 vector <edge> used; 36 ll cnt = 0, ans = 0; 37 for (ll i = 0; i <= n; i++) f[i] = i; 38 for (auto it : e) { 39 ll u = find(it.u), v = find(it.v); 40 if (u != v) { 41 ll z = 0; 42 if (z == it.v) a.push_back(it.u); 43 if (z == it.u) a.push_back(it.v); 44 if (z != it.u && z != it.v) used.push_back(it); 45 cnt++; f[u] = v; ans += it.w; 46 } 47 if (cnt == n) break; 48 } 49 cout << ans << endl; 50 cout << a.size() << endl; 51 for (auto it : a) printf("%lld ", it); 52 puts(""); 53 cout << used.size() << endl; 54 for (auto it : used) printf("%lld %lld ", it.u, it.v); 55 return 0; 56 }