题目链接:https://codeforces.com/problemset/problem/1245/D
大致思路:
- prim比kruskal快很多,所以用了prim。prim一个样例基本50ms就跑出来了,kruskal要300+ms
- 贪心,肯定是需要一个城市自建发电站的,那么选取一个花费最少的城市修建发电站
- city结构体记录是键发电站,还是连接城市
- 每次照prim模板更新dist就可以了
- 连线的前驱结点,遍历城市,如果花费和找到点的花费相同,那么就能作为前驱结点
- 开long long,我一开始开的int,花费那儿爆掉了
代码:
//#include<bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#include<string>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 2e3 + 5;
const int INF = 0x3f3f3f3f;
struct City {
PII pos;
ll id;//城市的编号
ll ci;//题意中的ci
ll ki;//题意中的ki
ll flg;//0表示选择ci 1表示选择ki
bool st = false;//是否加入到了连通集合
bool operator<(const City &C)const {
return ci < C.ci;//用来找选取的第一个自建发电站的城市
}
} city[N];
int n;
ll dist[N];
ll cnt;//添加城市的编号
set<PII> reck;//flg == 1 连线
set<ll> recc;//flg == 0 自建发电站
inline ll kcost(City x, City y) {//计算两个城市连电缆的花费
return (x.ki + y.ki) * (abs(x.pos.first - y.pos.first) + abs(x.pos.second - y.pos.second));
}
ll prim() {
memset(dist, 0x3f, sizeof dist);
dist[0] = city[0].ci;
recc.insert(city[0].id);
city[0].st = true;
for (int i = 1; i < n; i++) {
if (!city[i].st) {
if (dist[i] >= city[i].ci) {
dist[i] = city[i].ci;
city[i].flg = 0;
}
if (dist[i] > kcost(city[0], city[i])) {
dist[i] = kcost(city[0], city[i]);
city[i].flg = 1;
}
}
}
ll ans = city[0].ci;
for (int i = 1; i < n; i++) {
int t = -1;
for (int j = 1; j < n; j++)
if (!city[j].st && (t == -1 || dist[t] > dist[j])) {
t = j;
}
if (city[t].flg) {
for (int j = 0; j < n; j++) {
if (kcost(city[j], city[t]) == dist[t])
reck.insert({min(city[t].id, city[j].id), max(city[t].id, city[j].id)});
//这里min和max很重要,保持有序,防止出现答案中(a,b) (b,a)这样的连两次的情况
}
} else
recc.insert(city[t].id);
ans += dist[t];
//更新dist模板
for (int j = 1; j < n; j++) {
if (!city[j].st) {
if (dist[j] >= city[j].ci) {
dist[j] = city[j].ci;
city[j].flg = 0;
}
if (dist[j] > kcost(city[t], city[j])) {
dist[j] = kcost(city[t], city[j]);
city[j].flg = 1;
}
}
}
city[t].st = true;
}
return ans;
}
int main(void) {
scanf("%d", &n);
for (int i = 0; i < n; i++) {
int x, y;
scanf("%d%d", &x, &y);
city[i].pos = {x, y};
city[i].id = ++cnt;
}
for (int i = 0; i < n; i++)
scanf("%lld", &city[i].ci);
for (int i = 0; i < n; i++)
scanf("%lld", &city[i].ki);
sort(city, city + n);
cout << prim() << endl;
cout << recc.size() << endl;
for (auto i : recc)
cout << i << " ";
cout << endl << reck.size() << endl;
for (auto i : reck)
cout << i.first << " " << i.second << endl;
return 0;
}