题目大意:将k对点两两相连,求最小长度
易证得,最优方案中,相连的办公楼一定是取相邻的比取不相邻的要更优
然后就可以用贪心来做这道题了。。
之前向CZL大神学习了用堆来贪心的做法orz
大概思路就是将初始所有的线段放进堆里
每次取最短的线段进行连接,且ans+=a[i]
取完后删除当前线段,与相邻的两条线段,同时再插入新边,权值为a[pre]+a[next]-a[now]
其作用与最大流中的反向弧有点像,下一次若取到这条边,即ans+=a[pre]+a[next]-a[now]
很明显a[now]与之前抵消了,即不取now,反而取相邻的两条边去了
1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 #include<queue> 5 using namespace std; 6 const int maxn = 200020*2; 7 struct node{ 8int id; 9 };10 priority_queue<node> Q;11 int pre[maxn],next[maxn],k,a[maxn],n;12 bool del[maxn];13 int tot,last,now,ans;14 15 bool operator<(node x, node y){16return a[x.id]>a[y.id];17 }18 19 int main(){20scanf("%d%d", &n, &k);21scanf("%d", &last);22tot=0;23for (int i=1; i<n; i++){24 scanf("%d", &now);25 a[++tot]=now-last;26 last=now;27}28for (int i=1; i<n; i++){29 Q.push((node){i});30 pre[i]=i-1; next[i]=i+1;31}32pre[1]=next[tot]=0;33a[0]=1002000000; // Attention:不能是maxlongint,因为后面a[++tot]会爆 34while (k--){35 while (!Q.empty() && del[Q.top().id]) Q.pop();36 if (Q.empty()) break;37 int now=Q.top().id; ans+=a[now]; Q.pop();38 39 int l=pre[now],r=next[now];40 del[now]=del[l]=del[r]=1;41 42 a[++tot]=a[l]+a[r]-a[now]; Q.push((node){tot});43 44 pre[tot]=pre[l]; next[tot]=next[r];45 if (pre[tot]) next[pre[tot]]=tot;46 if (next[tot]) pre[next[tot]]=tot;47}48printf("%d\n", ans);49return 0;50 }