bzoj1150 [CTSC2007]数据备份
Description
你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份。然而数据备份的工作是枯燥乏味的,因此你想设计一个系统让不同的办公楼彼此之间互相备份,而你则坐在家中尽享计算机游戏的乐趣。已知办公楼都位于同一条街上。你决定给这些办公楼配对(两个一组)。每一对办公楼可以通过在这两个建筑物之间铺设网络电缆使得它们可以互相备份。然而,网络电缆的费用很高。当地电信公司仅能为你提供 K 条网络电缆,这意味着你仅能为 K 对办公楼(或总计2K个办公楼)安排备份。任一个办公楼都属于唯一的配对组(换句话说,这 2K 个办公楼一定是相异的)。此外,电信公司需按网络电缆的长度(公里数)收费。因而,你需要选择这 K 对办公楼使得电缆的总长度尽可能短。换句话说,你需要选择这 K 对办公楼,使得每一对办公楼之间的距离之和(总距离)尽可能小。下面给出一个示例,假定你有 5 个客户,其办公楼都在一条街上,如下图所示。这 5 个办公楼分别位于距离大街起点 1km, 3km, 4km, 6km 和 12km 处。电信公司仅为你提供 K=2 条电缆。
上例中最好的配对方案是将第 1 个和第 2 个办公楼相连,第 3 个和第 4 个办公楼相连。这样可按要求使用 K=2 条电缆。第 1 条电缆的长度是 3km-1km=2km ,第 2 条电缆的长度是 6km-4km=2km。这种配对方案需要总长 4km 的网络电缆,满足距离之和最小的要求。
Input
输入的第一行包含整数n和k,其中n(2 ≤ n ≤100 000)表示办公楼的数目,k(1≤ k≤ n/2)表示可利用的网络电缆的数目。接下来的n行每行仅包含一个整数(0≤ s ≤1000 000 000), 表示每个办公楼到大街起点处的距离。这些整数将按照从小到大的顺序依次出现。
Output
输出应由一个正整数组成,给出将2K个相异的办公楼连成k对所需的网络电缆的最小总长度。
Sample Input
5 2
1
3
4
6
12
1
3
4
6
12
Sample Output
4
正解:堆+链表模拟费用流。
很显然,只有相邻两点之间会有边,所以这是一个二分图的模型。
但是直接跑费用流会挂,所以我们考虑优化。
因为这个图比较简单,所以我们可以用堆+链表来模拟费用流。
我们每次在堆里取一条最短路,增广一条路以后,这条路会反过来,那么我们把它的相反数和它在链上的前后两点的路径值加起来,建一个新点丢到堆里就行了。
感觉讲起来很玄学。。还是推荐一个博客吧:http://www.cnblogs.com/GXZlegend/p/7128426.html
1 //It is made by wfj_2048~ 2 #include <algorithm> 3 #include <iostream> 4 #include <cstring> 5 #include <cstdlib> 6 #include <cstdio> 7 #include <vector> 8 #include <cmath> 9 #include <queue> 10 #include <stack> 11 #include <map> 12 #include <set> 13 #define inf (1<<30) 14 #define N (500010) 15 #define il inline 16 #define RG register 17 #define ll long long 18 19 using namespace std; 20 21 struct data{ 22 23 int x; ll val; 24 25 il bool operator < (const data &a) const{ 26 return val>a.val; 27 } 28 29 }; 30 31 priority_queue <data> Q; 32 33 int lst[N],nxt[N],del[N],n,k,tot; 34 ll dis[N],val[N],ans; 35 36 il int gi(){ 37 RG int x=0,q=1; RG char ch=getchar(); 38 while ((ch<'0' || ch>'9') && ch!='-') ch=getchar(); 39 if (ch=='-') q=-1,ch=getchar(); 40 while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); 41 return q*x; 42 } 43 44 int main(){ 45 #ifndef ONLINE_JUDGE 46 freopen("backup.in","r",stdin); 47 freopen("backup.out","w",stdout); 48 #endif 49 n=gi(),k=gi(),tot=n-1; 50 for (RG int i=1;i<=n;++i) dis[i]=gi(),lst[i]=i-1,nxt[i]=i+1; 51 for (RG int i=1;i<n;++i) Q.push((data){i,val[i]=dis[i+1]-dis[i]}); 52 nxt[n-1]=nxt[n]=0; 53 while (k--){ 54 while (del[Q.top().x]) Q.pop(); RG int x=Q.top().x; Q.pop(); 55 ans+=val[x],del[x]=del[lst[x]]=del[nxt[x]]=1; 56 if (!lst[x]) lst[nxt[nxt[x]]]=0; 57 else if (!nxt[x]) nxt[lst[lst[x]]]=0; else{ 58 val[++tot]=val[lst[x]]+val[nxt[x]]-val[x]; 59 lst[tot]=lst[lst[x]],nxt[tot]=nxt[nxt[x]]; 60 if (lst[tot]) nxt[lst[tot]]=tot; 61 if (nxt[tot]) lst[nxt[tot]]=tot; 62 Q.push((data){tot,val[tot]}); 63 } 64 } 65 printf("%lld\n",ans); return 0; 66 }