【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 }