题目描述
你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份。然而数据备份的工作是枯燥乏味的,因此你想设计一个系统让不同的办公楼彼此之间互相备份,而你则坐在家中尽享计算机游戏的乐趣。
已知办公楼都位于同一条街上。你决定给这些办公楼配对(两个一组)。每一对办公楼可以通过在这两个建筑物之间铺设网络电缆使得它们可以互相备份。
然而,网络电缆的费用很高。当地电信公司仅能为你提供 K 条网络电缆,这意味着你仅能为 K 对办公楼(或总计 2K 个办公楼)安排备份。任一个办公楼都属于唯一的配对组(换句话说,这 2K 个办公楼一定是相异的)。
此外,电信公司需按网络电缆的长度(公里数)收费。因而,你需要选择这 K对办公楼使得电缆的总长度尽可能短。换句话说,你需要选择这 K 对办公楼,使得每一对办公楼之间的距离之和(总距离)尽可能小。
下面给出一个示例,假定你有 5 个客户,其办公楼都在一条街上,如下图所示。这 5 个办公楼分别位于距离大街起点 1km, 3km, 4km, 6km 和 12km 处。电信公司仅为你提供 K=2 条电缆。
上例中最好的配对方案是将第 1 个和第 2 个办公楼相连,第 3 个和第 4 个办公楼相连。这样可按要求使用 K=2 条电缆。第 1 条电缆的长度是 3km―1km = 2km,第 2 条电缆的长度是 6km―4km = 2 km。这种配对方案需要总长 4km 的网络电缆,满足距离之和最小的要求。
输入输出格式
输入格式:
输入文件的第一行包含整数 n 和 k,其中 n(1≤n≤100 000)表示办公楼的数目,k(1≤k≤n/2)表示可利用的网络电缆的数目。
接下来的 n 行每行仅包含一个整数(0≤s≤1000 000 000), 表示每个办公楼到大街起点处的距离。这些整数将按照从小到大的顺序依次出现。
输出格式:
输出文件应当由一个正整数组成,给出将 2K 个相异的办公楼连成 K 对所需的网络电缆的最小总长度。
输入输出样例
输入样例#1:
5 2
1
3
4
6
12
输出样例#1:
4
说明
30%的输入数据满足 n≤20。
60%的输入数据满足 n≤10 000
题解
因为任一个办公楼都属于唯一的配对组,那么只与相邻公司相连才能保证答案最优
考虑贪心的思想,每次选择距离最近的相连(然而这样连样例都过不了)
我们因此发现,若选择某一段距离,会导致与之相邻的两段均不可选,这就需要我们改变贪心的策略,当选取某段距离比选取与之相邻距离更优的时候,我们才选择它
但在贪心的过程中,我们很难判断选择当前距离还是选择与之相邻距离更优,我们不妨给自己一个反悔的机会,在选择了距离 L 后,向队列中加入L1+L2-L(L1,L2为与L相邻的两段),当它们同时被选择的时候,相当于选择距离L相邻的两段
代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <vector>
#define N 100005
#define inf 2000000000
#define ll long long
using namespace std;
int n,k,a[N];
int last[N],nxt[N];
ll ans,L[N];
bool flag[N];
struct node
{
ll l;
int num;
friend bool operator > (node x,node y) {return x.l>y.l;}
}t[N];
priority_queue<node,vector<node>,greater<node> >q;
int main()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
L[i-1]=a[i]-a[i-1];
}
L[0]=inf;L[n]=inf;
for(int i=0;i<=n;i++)
{
t[i].num=i;t[i].l=L[i];
q.push(t[i]);
last[i]=i-1;nxt[i]=i+1;
}
for(int i=1;i<=k;i++)
{
node tmp=q.top();q.pop();
int p=tmp.num;
while(flag[p])
{
tmp=q.top();p=tmp.num;
q.pop();
}
ans+=tmp.l;
int lt=last[p],nt=nxt[p];
nxt[last[lt]]=p;last[nxt[nt]]=p;
last[p]=last[lt];nxt[p]=nxt[nt];
flag[lt]=flag[nt]=1;
L[p]=L[lt]+L[nt]-L[p];
tmp.num=p;tmp.l=L[p];
q.push(tmp);
}
printf("%lld",ans);
return 0;
}