码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2016-05-06 21:50:00      阅读:281      评论:0      收藏:0      [点我收藏+]

标签:

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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!