标签:
题目大意:将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{ 8 int 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){ 16 return a[x.id]>a[y.id]; 17 } 18 19 int main(){ 20 scanf("%d%d", &n, &k); 21 scanf("%d", &last); 22 tot=0; 23 for (int i=1; i<n; i++){ 24 scanf("%d", &now); 25 a[++tot]=now-last; 26 last=now; 27 } 28 for (int i=1; i<n; i++){ 29 Q.push((node){i}); 30 pre[i]=i-1; next[i]=i+1; 31 } 32 pre[1]=next[tot]=0; 33 a[0]=1002000000; // Attention:不能是maxlongint,因为后面a[++tot]会爆 34 while (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 } 48 printf("%d\n", ans); 49 return 0; 50 }
bzoj1150: [CTSC2007]数据备份Backup--贪心+优先队列维护堆
标签:
原文地址:http://www.cnblogs.com/mzl120918/p/5467132.html