【bzoj1150】[CTSC2007]数据备份Backup

将k对点两两相连,求最小长度

 

易证得,最优方案中,相连的办公楼一定是取相邻的比取不相邻的要更优

然后就可以用贪心来做这道题了。。

 

将初始所有的线段放进堆里

每次取最短的线段进行连接,且ans+=a[i]

取完后删除当前线段,与相邻的两条线段,同时再插入新边,权值为a[pre]+a[next]-a[now]

其作用与最大流中的反向弧有点像,下一次若取到这条边,即ans+=a[pre]+a[next]-a[now]

很明显a[now]与之前抵消了,即不取now,反而取相邻的两条边去了

 

 1 #include<algorithm>
 2 #include<iostream>
 3 #include<cstdlib>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<cmath>
 7 #include<queue>
 8 using namespace std;
 9  
10 #define INF 1000000010
11 #define N 200010
12  
13 struct Node
14 {
15     int id;
16 };
17  
18 priority_queue<Node>q;
19  
20 int n,m,k;
21 int a[N],next[N],pre[N];
22  
23 bool v[N];
24  
25 int ans,now,cnt,last;
26  
27 bool operator < (Node x,Node y)
28 {
29     return a[x.id]>a[y.id];
30 }
31  
32 int main()
33 {
34     scanf("%d%d",&n,&k);
35     scanf("%d",&last);
36     for (int i=1;i<n;i++)
37     {
38         scanf("%d",&now);
39         a[++cnt]=now-last;
40         last=now;
41     }
42     for (int i=1;i<n;i++)
43     {
44         q.push((Node){i});
45         pre[i]=i-1;
46         next[i]=i+1;
47     }
48     pre[1]=next[cnt]=0;
49     a[0]=INF;
50     while (k--)
51     {
52         while (!q.empty() && v[q.top().id])
53             q.pop();
54         if (q.empty())
55             break;
56         now=q.top().id;
57         ans+=a[now];
58         q.pop();
59         int l=pre[now],r=next[now];
60         v[now]=v[l]=v[r]=true;
61         a[++cnt]=a[l]+a[r]-a[now];
62         q.push((Node){cnt});
63         pre[cnt]=pre[l];
64         next[cnt]=next[r];
65         if (pre[cnt])
66             next[pre[cnt]]=cnt;
67         if (next[cnt])
68             pre[next[cnt]]=cnt;
69     }
70     printf("%d",ans);
71     return 0;
72 }

 

posted @ 2016-05-14 14:23  Yangjiyuan  阅读(148)  评论(0编辑  收藏  举报