CF1245D: Shichikuji and Power Grid
题意描述:
- 给定(n)个点((nleq2000)),在第(i)个点上建立一个基站需要(c_i)的代价,连接两个点需要((|x_i-x_j|+|y_i-y_j|)*(k_i+k_j))的代价。对于一个点要么建立基站,要么连接建立基站的点。问最小代价是多少,同时输出建立基站的点和线路。
思路:
- 建立一个超级根,对于每个城市建立发电站,连接一条权值为(c_i)的边,再把每个城市之间连接电线的花费算出来,跑(kruskal)。
- 在跑的过程中记录哪些城市建立了发电站,哪些城市建立了电线。
- (hint:)注意开(long long)
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2000 + 10;
int n;
ll ans, x[maxn], y[maxn], k[maxn], c[maxn];
struct Node{
int x, y;
ll z;
}p[maxn*maxn];
int tot;
void add_edge(int x, int y, ll z){
p[++tot].x = x, p[tot].y = y, p[tot].z = z;
}
int fa[maxn];
bool cmp(Node a, Node b){
return a.z < b.z;
}
int get_fa(int x)
{
if(x == fa[x]) return x;
return fa[x] = get_fa(fa[x]);
}
int ans1[maxn], cnt1;
int ax[maxn], ay[maxn], cnt2;
void kruskal()
{
for(int i = 0; i <= n; i++) fa[i] = i;
sort(p+1, p+1+tot, cmp);
int cnt = 0;
for(int i = 1; i <= tot; i++)
{
int x = p[i].x, y = p[i].y;
ll z = p[i].z;
int fx = get_fa(x), fy = get_fa(y);
if(fx != fy)
{
if(x == 0 || y == 0) ans1[++cnt1] = x + y;
else ax[++cnt2] = x, ay[cnt2] = y;
ans += z; fa[fx] = fy; cnt++;
}
if(cnt == n) break;
}
cout << ans << endl;
}
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%lld%lld", &x[i], &y[i]);
for(int i = 1; i <= n; i++) scanf("%lld", &c[i]);
for(int i = 1; i <= n; i++) scanf("%lld", &k[i]);
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
{
if(i != j)
{
ll w = (k[i] + k[j]) * (abs(x[i]-x[j]) + abs(y[i]-y[j]));
add_edge(i, j, w);
}
}
for(int i = 1; i <= n; i++)
add_edge(0, i, c[i]), add_edge(i, 0, c[i]);
kruskal();
cout << cnt1 << endl;
for(int i = 1; i <= cnt1; i++)
printf("%d ", ans1[i]); puts("");
cout << cnt2 << endl;
for(int i = 1; i <= cnt2; i++)
printf("%d %d
", ax[i], ay[i]);
return 0;
}