数据备份 CH Round #53 -【Nescafé 32】杯NOIP模拟赛
描述
已知有N座办公楼位于同一条街上。你决定给这些办公楼配对(两个一组)。每一对办公楼可以通过在这两个建筑物之间铺设网络电缆使得它们可以互相备份。然而,网络电缆的费用很高。当地电信公司仅能为你提供K条网络电缆,这意味着你仅能为K对办公楼(或总计2K个办公楼)安排备份。任一个办公楼都属于唯一的配对组(换句话说,这2K个办公楼一定是相异的)。 此外,电信公司需按网络电缆的长度(公里数)收费。因而,你需要选择这K对办公楼使得电缆的总长度尽可能短。换句话说,你需要选择这K对办公楼,使得每一对办公楼之间的距离之和(总距离)尽可能小。
输入格式
输入的第一行包含整数n和k,n表示办公楼的数目,k表示可利用的网络电缆的数目。
接下来的n行每行包含一个整数s, 表示每个办公楼到大街起点处的距离。这些整数将按照从小到大的顺序依次出现。
输出格式
一个正整数,表示将2K个相异的办公楼连成k对所需的网络电缆的最小总长度。
样例输入
5 2 1 3 4 6 12
样例输出
4(即3-1+6-4)
数据范围与约定
- 对于30%的数据,N<=20。
- 对于60%的数据,N<=10000。
- 对于100%的数据,N<=100000,1<=k<=n/2,0<=s<=10^9。
哎,这道题第一感觉是dp,然后就写了一个……知道数据太大,所以也就没想得满分
可是写完后发现错误百出,先是数组的范围,然后是dp的边界……终于不懈努力,拿了55
下面我们说一下dp的做法
看到题,我们很快就能想出来一个最有结构问题,即,从0~i最优必然是要有0~i-1最优;
很明显,我们可以把状态定为f[i][j]表示0~i选j个线段的最小长度,
那么对于每一个状态必然有:
(1)i与前一个连
(2)i与后一个连
(3)i不连
我们就有了一个dp方程:
f[i][j]=min(f[i-1][j],f[i-2][j-1]+a[i]-a[i-1])
+++++++++++++代码如下++++++++++++++++++
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#define INF 0x3f3f3f3f
using namespace std;
int f[20000][1000],a[50000];//鄙人不才,dp只能写到55了,哎!费了好大劲
int n,k;
int main()
{
scanf("%d%d",&n,&k);
for (int i=1;i<=n;i++)cin>>a[i];
for (int i=0;i<=n;i++)f[i][0]=0;//从这儿往下一定要注意dp的边界问题!坑毁我了
for (int j=1;j<=k;j++)f[0][j]=INF;
for (int i=1;i<=n;i++)
for (int j=1;j<=k;j++)
if (i>1)f[i][j]=min(f[i-1][j],f[i-2][j-1]+a[i]-a[i-1]);
else f[i][j]=f[i-1][j];
printf("%d",f[n][k]);
return 0;
}
++++++++++++++++++++++++++++++++++++++
为了ac这道题,作者从网上找了ac的题解,大概有两种做法——贪心和网络流
由于作者不会写网络流所以下面主要介绍贪心的方法,日后,网络流的做法将会更新。