[APIO/CTSC 2007]数据备份(贪心+堆)
你在一家 IT 公司為大型寫字樓或辦公樓(offices)的計算機數據做備份。然而數據備份的工作是枯燥乏味的,因此你想設計一個系統讓不同的辦公樓彼此之間互相備份,而你則坐在家中盡享計算機游戲的樂趣。
已知辦公樓都位于同一條街上。你決定給這些辦公樓配對(兩個一組)。每一對辦公樓可以通過在這兩個建筑物之間鋪設網絡電纜使得它們可以互相備份。
然而,網絡電纜的費用很高。當地電信公司僅能為你提供 K 條網絡電纜,這意味著你僅能為 K 對辦公樓(或總計 2K 個辦公樓)安排備份。任一個辦公樓都屬于唯一的配對組(換句話說,這 2K 個辦公樓一定是相異的)。
此外,電信公司需按網絡電纜的長度(公里數)收費。因而,你需要選擇這 K對辦公樓使得電纜的總長度盡可能短。換句話說,你需要選擇這 K 對辦公樓,使得每一對辦公樓之間的距離之和(總距離)盡可能小。
下面給出一個示例,假定你有 5 個客戶,其辦公樓都在一條街上,如下圖所示。這 5 個辦公樓分別位于距離大街起點 1km, 3km, 4km, 6km 和 12km 處。電信公司僅為你提供 K=2 條電纜。
Solution
通過觀察我們發現最優解只可能是兩個相鄰的點。
問題轉化成了給一些點,選出其中m個使他們在互不相鄰的前提下權值和最小。
這讓我想到了一道題叫種樹,然后發現一毛一樣2333。
考慮選擇一個點后,兩邊都不能選了,但最優解有可能屬于兩邊。
我們從堆里取出最小的點,把兩邊的點刪掉,用兩邊的點權之和減去當前點的權值最為這個點的權值放進堆里,繼續貪心。
為什么這樣是對的,因為當我貪心的選擇了一個點后,兩邊的點要么都選,要么都不選,如果只選一個,還不如只選中間點呢。
注意因為要取最小值,所以注意判一下邊界。
Code
#include<iostream> #include<cstdio> #include<queue> #define mm make_pair #define N 100002 using namespace std; priority_queue<pair<long long,int> >q; int n,k,l[N],r[N]; long long ans,a[N]; bool ji[N]; int main(){scanf("%d%d",&n,&k);for(int i=1;i<=n;++i)scanf("%d",&a[i]);n--;for(int i=1;i<=n;++i){a[i]=a[i+1]-a[i],q.push(mm(-a[i],i));l[i]=i-1;r[i]=i+1;}a[0]=a[n+1]=0x7f7f7f7f; for(int i=1;i<=k;++i){ int x=q.top().second,y=q.top().first;q.pop();while(ji[x]){x=q.top().second;y=q.top().first;q.pop();}ans-=y;a[x]=a[l[x]]+a[r[x]]-a[x];q.push(mm(-a[x],x));ji[l[x]]=ji[r[x]]=1;l[x]=l[l[x]];r[l[x]]=x;r[x]=r[r[x]];l[r[x]]=x;}cout<<ans; }?
轉載于:https://www.cnblogs.com/ZH-comld/p/9590804.html
總結
以上是生活随笔為你收集整理的[APIO/CTSC 2007]数据备份(贪心+堆)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: setTimeout保证浏览器可以实时接
- 下一篇: 33.JAVA编程思想——JAVA IO