快餐店

题目描述:

排成一条直线的公路上有N个加油站,为了方便加油站的员工吃饭,需要在这N个加油站点位置选K个开设快餐店。那么问题来了,怎样选取能使得每个加油站都可以就近吃饭。所谓的就近吃饭,就是每个加油站的人员会去最近的快餐店吃饭,需要走两个加油站之间的距离。我们的目标是让每个加油站到最近快餐店的距离之和最小(具体可以看样例解释)。

 

输入:

输入N, K
然后接下来N行,每行输入一个整数ai,表示加油站的位置(这个位置的值是递增的)

 

输出:

输出最小的距离之和,格式见样例输出。

 

样例输入:

6 3
5
6
12
19
20
27

 

样例输出:

Total distance sum = 8

 

分段时,每段的数量有限制的题型,使用分段DP的方法。可以将问题划分子问题为区间[1,i]划分成j段,最少需要多少代价,那么我们可以用数组dp[i][j]表示前i个快餐店分成j段的最小代价,转移方程为:
dp[i][len]=min(dp[i][len],dp[j][len-1]+cost[j+1][i]);
在这之前,我们需要预处理出[i,j]这一段需要的代价,用cost[i][j]表示。这段区间,快餐店应该设在中位数所在的站点,会使得区间[i,j]一段的代价最小。
综上,我们就可以用分段DP的方式了(哈哈哈哈哈哈哈哈哈哈哈哈哈哈啊哈哈):

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m,a[205],dp[205][35],cost[205][205];
int zxy()
{
for(int i=1;i<=n;i++)
{
    dp[i][1]=cost[1][i];
    for(int j=2;j<=m;j++)dp[i][j]=100000000;
}
for(int len=2;len<=m;len++)
for(int i=len;i<=n;i++)
for(int j=len-1;j<=i-1;j++)
{
    dp[i][len]=min(dp[i][len],dp[j][len-1]+cost[j+1][i]);
}
return dp[n][m];
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j++)
{
    int mid=(i+j)>>1;
    cost[i][j]=0;
    for(int k=i;k<=j;k++)
    cost[i][j]+=abs(a[mid]-a[k]);
}
int res=zxy();
printf("Total distance sum = %d\n",res);
return 0;
} 

 

posted @ 2017-12-19 19:45  Zhoier  阅读(356)  评论(0编辑  收藏  举报