900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > bzoj1150: [CTSC]数据备份Backup--贪心+优先队列维护堆

bzoj1150: [CTSC]数据备份Backup--贪心+优先队列维护堆

时间:2024-02-22 22:49:38

相关推荐

bzoj1150: [CTSC]数据备份Backup--贪心+优先队列维护堆

题目大意:将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 }

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。