ACWING147. 数据备份(贪心,堆)

你在一家IT公司为大型写字楼或办公楼的计算机数据做备份。

然而数据备份的工作是枯燥乏味的,因此你想设计一个系统让不同的办公楼彼此之间互相备份,而你则坐在家中尽享计算机游戏的乐趣。

已知办公楼都位于同一条街上,你决定给这些办公楼配对(两个一组)。

每一对办公楼可以通过在这两个建筑物之间铺设网络电缆使得它们可以互相备份。

然而,网络电缆的费用很高。

当地电信公司仅能为你提供 K 条网络电缆,这意味着你仅能为 K 对办公楼(总计2K个办公楼)安排备份。

任意一个办公楼都属于唯一的配对组(换句话说,这 2K 个办公楼一定是相异的)。

此外,电信公司需按网络电缆的长度(公里数)收费。

因而,你需要选择这 K 对办公楼使得电缆的总长度尽可能短。

换句话说,你需要选择这 K 对办公楼,使得每一对办公楼之间的距离之和(总距离)尽可能小。

下面给出一个示例,假定你有 5 个客户,其办公楼都在一条街上,如下图所示。

这 5 个办公楼分别位于距离大街起点 1km, 3km, 4km, 6km 和 12km 处。

电信公司仅为你提供 K=2 条电缆。

1111.png

上例中最好的配对方案是将第 1 个和第 2 个办公楼相连,第 3 个和第 4 个办公楼相连。

这样可按要求使用 K=2 条电缆。

第 1 条电缆的长度是 3km-1km=2km ,第 2 条电缆的长度是 6km-4km=2km。

这种配对方案需要总长 4km 的网络电缆,满足距离之和最小的要求。

输入格式
第一行输入整数n和k,其中 n 表示办公楼的数目,k 表示可利用的网络电缆的数目。

接下来的n行每行仅包含一个整数s,表示每个办公楼到大街起点处的距离。

这些整数将按照从小到大的顺序依次出现。

输出格式
输出应由一个正整数组成,给出将2K个相异的办公楼连成k对所需的网络电缆的最小总长度。

数据范围
2≤n≤100000,
1≤k≤n/2,
0≤s≤1000000000
输入样例:
5 2
1
3
4
6
12
输出样例:
4

思路:
电缆肯定要连接在相邻办公楼之间,否则肯定有替换的方法减少电缆长度。那么我们就得到了n-1个数,且取的数不能相邻。

类比最小生成树的取法,猜想能否取每次最小的数?

对于 8 2 1 2 8 这个数据却是不行,取完了1,后面只能取8了。这种情况下最小数左右的数我们无法考虑到了。

也就是说,我们需要考虑取最小数和取最小数两边数的方案。
而要取完1以后,把1替换成3,并且删掉2,2。就能同时考虑到取最小数的情况。

这个过程可以用链表和堆维护。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>

using namespace std;

typedef long long ll;

const int maxn = 1e5 + 7;
struct Node
{
    int id;
    ll val;
    bool operator<(const Node&rhs)const
    {
        return val > rhs.val;
    }
};

priority_queue<Node>q;
int lst[maxn],nex[maxn],vis[maxn];
ll a[maxn],to[maxn];

void link(int x,int y)
{
    nex[x] = y;lst[y] = x;
}

void solve(int id)
{
    int x = lst[id],y = id,z = nex[id];
    link(lst[x],y);link(y,nex[z]);
    to[y] = to[x] + to[z] - to[y];
    q.push(Node{id,to[y]});
//    lst[y]=lst[lst[y]];
//    nex[y]=nex[nex[y]];
//    nex[lst[y]]=y;
//    lst[nex[y]]=y;
    vis[x] = 1;vis[z] = 1;
}

int main()
{
    int n,k;scanf("%d%d",&n,&k);
    for(int i = 1;i <= n;i++)
    {
        scanf("%lld",&a[i]);
    }
    to[0] = to[n] = 1e9;
    for(int i = 1;i < n;i++)
    {
        to[i] = a[i + 1] - a[i];
        lst[i] = i - 1;
        nex[i] = i + 1;
        q.push(Node{i,to[i]});
    }
    ll ans = 0;
    for(int i = 1;i <= k;)
    {
        Node now = q.top();q.pop();
        int id = now.id;
        if(vis[id])continue;
        i++;
        ans += now.val;
        solve(id);
    }
    printf("%lld\n",ans);
    return 0;
}

发布了756 篇原创文章 · 获赞 27 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/tomjobs/article/details/104591341