问题 H: T-net

问题 H: T-net
时间限制: 1 Sec 内存限制: 128 MB
题目编号:10730

题目描述
T-net which is a new telecommunications company, plans to install its base stations in the city. The places where base stations must be installed have been already specified. T-net has two types of antennas to be used in the base stations: (i)antennas with transmission radius a, and (ii) antennas with transmission radius b. Two antennas can communicate with each other if and only if both are inside the coverage area of each other. Antenna with smaller transmission radius of course is cheaper. T-net plans to minimize its cost while keeping the whole network connected. Precisely, T-net plans to
minimize its cost which is the sum of the transmission radii of all antennas. Interestingly, all base-station places are on a line. Help T-net construct a connected network with the minimum cost.

输入
The first line of the input contains three positive integers n, a and b (1 ⩽ n ⩽ 105 and 1 ⩽ a, b ⩽ 105 ) where n is the number of base stations, and a and b are radii as defined in the problem statement. The second line contains n distinct coordinates of base stations on the line with respect to an origin on the line. All coordinates are positive integers not more than 105 .

输出
If it is possible to construct a connected network, print the minimum cost in the output. Otherwise, print -1 .

样例输入
3 1 3
1 4 3
样例输出
7

题目大意:一个坐标轴上有n个点(位置分别为第二行的坐标),有两种覆盖半径分别为a和b的基站,建造基站代价与覆盖半径相同,求使这些点联通的最小代价

题目分析:先将所有坐标排序,将a设为半径小的基站,显然地,如果一个点到两侧点距离都在a以内,则建立基站a,如果一个点到两侧点中任何一个距离大于b,则无法建立。对于其他点,我最初考虑的是判断该点到左右两个点的距离是否都在a以内,如果不是则建立b,但却会碰到一些问题:
4 1 10
1 9 10 20
对于这个样例,正解应为31(第二个建立1,其他均建立10),但按照我刚才的贪心方法会付出40的代价,因为第二个点虽然到左侧的距离超过了a,但它右侧的点已经和左侧联通,即它不必直接到达左侧点,连接右侧点的同时也连接了左侧的点。
因此,调整贪心策略:对一个取b的基站x,选取它能覆盖到点(x~x+b)当中的最右侧的点y建立b基站和他联通,再将中间的点连向xy这两个点。不难发现这个策略没有更优的情况:若x与x的下一个点距离超过a,则在x的下一个点到y之间必然存在至少一个点需要建立b基站与x相连,而将这个基站建在其他位置不会比y更好:y处同时考虑到了之后的点的需求。而对于x与下一个点不超过a的情况(即x是因为x前面的点取了b基站),会在中间点连两端的时候将b重设为a。
中间点连向两端的方法:先从左右两侧向内遍历,左侧:从左端点开始用半径为a的基站连接,直到第一个距离大于a的为止(此时如果可以用a将左右端点直接连通,则将右端点基站改为a),再从右侧向左寻找,若还剩余节点,则从左开始将第一个节点建立b基站,从左到右寻找,直到全部建立基站为止。

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N=1e5+5;
int c[N];
ll d[N];
int main()
{
    int n,a,b;
    cin>>n>>a>>b;
    if(a>b) swap(a,b);
    for(int i=1;i<=n;i++)
    {
        cin>>c[i];
    }
    if(n==1)
    {
        cout<<min(a,b);
        return 0;
    }
    sort(c+1,c+1+n);
    c[n+1]=c[n];
    c[0]=c[1];
    ll ans=0;
    int r=0;
    for(int i=1;i<=n;i++)
    {
        if(d[i]) continue;
        if(c[i]-c[i-1]<=a&&c[i+1]-c[i]<=a)
        {
            d[i]=a;//ans+=a;
            continue;
        }
        if(c[i]-c[i-1]>b&&c[i+1]-c[i]>b)
        {
            cout<<-1;
            return 0;
        }
 
        d[i]=b;
        while(d[i]==b)
        {
            int j;
            for(j=i;c[j]<=c[i]+b&&j<=n;j++);
            j--;
            bool flag=true;
            for(int k=i+1;k<j;k++)
            {
                if(c[k]-c[k-1]>a||c[k+1]-c[k]>a)
                {
                    flag=false;
                    break;
                }
            }
            if(flag)
            {
                break;
            }
            d[j]=b;
            int l=i,r=j;
            for(l=i+1;l<j;l++)
            {
                if(c[l]-c[l-1]<=a)
                    d[l]=a;
                else  break;
            }
            for(r=j-1;r>i;r--)
            {
                if(d[r]) break;
                if(c[r+1]-c[r]<=a)
                    d[r]=a;
                else break;
            }
            while(l<=r)
            {
                d[l]=b;
                l++;
                for(;l<=r;l++)
                {
                    if(c[l]-c[l-1]<=a)
                        d[l]=a;
                    else  break;
                }
 
            }
            i=j;
        }
    }
    for(int i=1;i<=n;i++)
        ans+=d[i];
    cout<<ans<<endl;
    return 0;
}
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值