描述:
XXX乡有n个村,政府希望在每个村设立一个通讯基站,使得各个村之间可以能够联络(只要两个村之间有直接或间接的线路即可连通)。
第i个村的基站所在的位置为(xi, yi),连接两个基站所需的成本为彼此之间距离的平方。
请帮助设计一个方案,使得总成本最低。
输入:
第一行为正整数n(1<=n<=1e5)。
接下来有n行,每行两个整数xi, yi(0<=xi<=1e6, 0<=yi<=10)。
输出:
输出最低成本。
大致思路:
存每个点之间的边,然后套最小生成树模板。
因为n的最大值为1e5,直接套两层循环存所有边会TLE和MLE。考虑只存一部分的边。
观察从左至右任意的三点A,B,C进行分析。发现有时A和C是没有必要相连的。当AC无需相连时,A和C后面的点也无需相连。那么按照这个思路,就能少存不少边。
何时AC才无需相连:只要保证其他的两条边比AC短即可(因为连接三点只需要两条边)即AB<AC和BC<AC。
对上述两个关系进行计算可得X(b)-X(a)>10&&X(c)-X(b)>10。所以我们先寻找B点(第一个距离A大于10的点),然后再根据B点去寻找C点(第一个距离B大于10的点),找到C点直接break退出内循环即可。
(注意开long long)
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;
void cincout()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
ll n;
int ac[100007], B;
struct Node
{
ll x, y;
}ver[100007];
struct node
{
ll x, y, z;
node(ll x1, ll y1, ll z1)
{
x = x1, y = y1, z = z1;
}
node() {}
};
vector<node>v;
ll qq(ll x)
{
return x * x;
}
ll dis(Node x, Node y)
{
return qq(x.x - y.x) + qq(x.y - y.y);
}
bool cmp(node x, node y)
{
return x.z < y.z;
}
bool cmp_ver(Node x, Node y)
{
return x.x < y.x;
}
int ff(int x)
{
int t1 = x, t2;
while (x != ac[x])
{
x = ac[x];
}
while (t1 != ac[t1])
{
t2 = t1;
t1 = ac[t1];
ac[t2] = x;
}
return x;
}
void un(int x, int y)
{
x = ff(x);
y = ff(y);
ac[y] = x;
}
int main()
{
cincout();
cin >> n;
for (int i = 1; i <= n; i++)
{
ac[i] = i;
cin >> ver[i].x >> ver[i].y;
}
sort(ver + 1, ver + 1 + n, cmp_ver);
for (int i = 1; i <= n; i++)
{
B = 0;
for (int j = i + 1; j <= n; j++)
{
if (B && ver[B].x + 10 < ver[j].x)break;
ll tmp = dis(ver[i], ver[j]);
v.emplace_back(i, j, tmp);
if (ver[i].x + 10 < ver[j].x)B = j;
}
}
sort(v.begin(), v.end(), cmp);
ll len = v.size(), ans = 0, x, y, z;
for (int i = 0; i < len; i++)
{
x = v[i].x, y = v[i].y, z = v[i].z;
if (ff(x) != ff(y))
{
un(x, y);
ans += z;
}
}
cout << ans;
return 0;
}