TZOJ 7573 通讯网络

描述:

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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值