题目大意
给你n个点,你可以在这个点上建站,也可以通过一条边将这个点与站点(直接/间接)连通。
解题思路
本题主要是考察建图技巧,因为每个点要么建站,要么与其他点连通,并且至少有一个站点,所以我们再加入一个点,这个点与所有点连通,并且花费是每个点建站的花费,然后再把所有点建一个完全图跑最小生成树就解决问题了。
代码
const int maxn = 2e3+10;
const int maxm = 1e7+10;
int n;
struct INFO {
int x, y;
} info[maxn];
int c[maxn], k[maxn], tot, p[maxn];
ll g[maxn][maxn], d[maxn];
bool vis[maxn];
ll prim() {
clr(d, 0x3f);
d[n+1] = 0;
int pre;
for (int i = 1; i<=n; ++i) {
int u = 0;
for (int j = 1; j<=n+1; ++j)
if (!vis[j] && (u==0 || d[j]<d[u])) u = j;
vis[u] = 1;
for (int v = 1; v<=n+1; ++v)
if (!vis[v] && d[v]>g[u][v]) {
p[v] = u;
d[v] = g[u][v];
}
}
ll sum = 0;
for (int i = 1; i<=n+1; ++i) sum += d[i];
return sum;
}
int main(){
cin >> n;
for (int i = 1; i<=n; ++i) cin >> info[i].x >> info[i].y;
for (int i = 1; i<=n; ++i) cin >> c[i];
for (int i = 1; i<=n; ++i) cin >> k[i];
for (int i = 1; i<=n; ++i) g[i][n+1] = g[n+1][i] = c[i];
for (int i = 1; i<=n; ++i)
for (int j = i+1; j<=n; ++j) {
ll d = 1LL*(abs(info[i].x-info[j].x)+abs(info[i].y-info[j].y))*(k[i]+k[j]);
g[i][j] = g[j][i] = d;
}
cout << prim() << endl;
vector<int> ans1;
vector<P> ans2;
for (int i = 1; i<=n; ++i) {
if (p[i]==n+1) ans1.push_back(i);
else ans2.push_back({p[i], i});
}
int sz = ans1.size();
cout << sz << endl;
for (int i = 0; i<sz; ++i) printf(i==sz-1 ? "%d
":"%d ", ans1[i]);
sz = ans2.size();
cout << sz << endl;
for (int i = 0; i<sz; ++i) printf("%d %d
", ans2[i].x, ans2[i].y);
return 0;
}