题意:给定n个点的坐标,要求连k条边,每个点仅可连一条边,求最小距离和。
优先队列维护相邻两点间的距离,每加一条边,将于这两点有关的三个值全删除(打标记),再将两边的值减去中间的值加入优先队列,用链表维护前后相邻的值。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <queue>
#include <cstdlib>
#include <cstring>
#define pa pair<int,int>
#define mp(a,b) make_pair(a,b)
#define N 100009
using namespace std;
int a[N];
int x[N],next[N],used[N],pre[N];
struct cmp
{
bool operator()(const pa a,const pa b)
{
return a.first>b.first;
}
};
int main()
{
priority_queue<pa,vector<pa>,cmp> q;
memset(used,0,sizeof(used));
int n,k;
cin>>n>>k;
for (int i=1;i<=n;i++)
cin>>a[i];
sort(a+1,a+n+1);
for (int i=1;i<n;i++)
x[i]=a[i+1]-a[i],next[i]=i+1,pre[i+1]=i;
for (int i=1;i<n;i++)
q.push(mp(x[i],i));
int ans=0;
for (int i=1;i<=k;i++)
{
pa y=q.top();
q.pop();
while (used[y.second])
{
y=q.top();
q.pop();
}
ans+=y.first;
if (pre[y.second]==0)
{
used[y.second]=used[next[y.second]]=1;
pre[next[next[y.second]]]=0;
continue;
}
if (next[y.second]==n)
{
used[y.second]=used[pre[y.second]]=1;
next[pre[pre[y.second]]]=n;
continue;
}
q.push(mp(x[pre[y.second]]+x[next[y.second]]-y.first,y.second));
x[y.second]=x[pre[y.second]]+x[next[y.second]]-y.first;
used[pre[y.second]]=1;
used[next[y.second]]=1;
pre[y.second]=pre[pre[y.second]];
next[y.second]=next[next[y.second]];
next[pre[y.second]]=y.second;
pre[next[y.second]]=y.second;
}
cout<<ans<<endl;
}