2014-08-10 23:30:04
Fast Food |
The fastfood chain McBurger owns several restaurants along a highway. Recently, they have decided to build several depots along the highway, each one located at a restaurent and supplying several of the restaurants with the needed ingredients. Naturally, these depots should be placed so that the average distance between a restaurant and its assigned depot is minimized. You are to write a program that computes the optimal positions and assignments of the depots.
To make this more precise, the management of McBurger has issued the following specification: You will be given the positions of nrestaurants along the highway as n integers (these are the distances measured from the company's headquarter, which happens to be at the same highway). Furthermore, a number
will be given, the number of depots to be built.
The k depots will be built at the locations of k different restaurants. Each restaurant will be assigned to the closest depot, from which it will then receive its supplies. To minimize shipping costs, the total distance sum, defined as
![\begin{displaymath}\sum_{i=1}^n \mid d_i - (\mbox{position of depot serving restaurant }i) \mid \end{displaymath}](http://uva.onlinejudge.org/external/6/662img3.gif)
must be as small as possible.
Write a program that computes the positions of the k depots, such that the total distance sum is minimized.
Input
The input file contains several descriptions of fastfood chains. Each description starts with a line containing the two integers n and k. n and kwill satisfy ,
,
. Following this will n lines containing one integer each, giving the positions di of the restaurants, ordered increasingly.
The input file will end with a case starting with n = k = 0. This case should not be processed.
Output
For each chain, first output the number of the chain. Then output an optimal placement of the depots as follows: for each depot output a line containing its position and the range of restaurants it serves. If there is more than one optimal solution, output any of them. After the depot descriptions output a line containing the total distance sum, as defined in the problem text.
Output a blank line after each test case.
Sample Input
6 3 5 6 12 19 20 27 0 0
Sample Output
Chain 1 Depot 1 at restaurant 2 serves restaurants 1 to 3 Depot 2 at restaurant 4 serves restaurants 4 to 5 Depot 3 at restaurant 6 serves restaurant 6 Total distance sum = 8
思路:这道题和之前的递推题是有异曲同工之妙的(类似的题目貌似在某个比赛里见过)。我一开始的思路是dp[i][j][k]记录从第i个到第j个饭店布置k个仓库的最小距离和,后来发现状态太多不好转移。
于是把表示区间的两个量压缩成一个,用dp[i][j]表示在前j个饭店布置i个仓库的最小距离和(这种前i个放j个东西的递推非常常见)。为什么要这样想呢?在分析一下:首先动态规划的核心思想就是通过
求出子问题在一定条件的下的最优解,来推出整个问题的最优解,特点是:子问题具有重复性(或者说子问题中包含着更子的问题,因为如果子问题相互独立就可用分治来处理),其次是子问题和整个问题可
建立递推关系,就像这题中的:在1 - j号饭店中放i - 1个仓库,与在(j+1) - n号饭店中放1个仓库,这两个子问题想加的最优解是可以构成整个问题的最优解的。
于是有:dp[i][j] = min(dp[i][j],dp[i - 1][p] + dis[p + 1][j]) (i - 1 <= p < j)
(这里的dis[x][y]表示在x - y号饭店中布置一个仓库的最小距离和,显然应该放在中间,若为饭店数为偶数,随便偏左偏右,易证)
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 #include <cmath> 5 using namespace std; 6 const int INF = 1e9; 7 8 int n,k; 9 int d[205]; 10 int dp[35][205]; 11 int dis[205][205]; 12 int path[35][205]; 13 int cnt; 14 15 int Cal(int x,int y){ 16 int sum = 0; 17 int mid = (x + y) / 2; 18 for(int i = x; i <= y; ++i) 19 sum += abs(d[i] - d[mid]); 20 return sum; 21 } 22 23 void Print(int x,int y){ 24 if(x == 0) 25 return; 26 Print(x - 1,path[x][y]); 27 printf("Depot %d at restaurant %d serves restaurants %d to %d\n",++cnt,(path[x][y] + 1 + y) / 2,path[x][y] + 1,y); 28 } 29 30 int main(){ 31 int Case = 0; 32 while(scanf("%d%d",&n,&k) == 2 && (n || k)){ 33 for(int i = 1; i <= n; ++i) 34 scanf("%d",&d[i]); 35 for(int i = 1; i <= n; ++i){ 36 for(int j = i; j <= n; ++j){ 37 dis[i][j] = Cal(i,j); 38 } 39 } 40 //dp[i][j] = min(dp[i][j],dp[i - 1][p] + dis[p + 1][j]) , (i - 1 <= p < j) 41 memset(dp,0,sizeof(dp)); 42 memset(path,0,sizeof(path)); 43 for(int j = 1; j <= n; ++j){ 44 dp[1][j] = dis[1][j]; 45 } 46 for(int i = 2; i <= k; ++i){ 47 for(int j = 1; j <= n; ++j){ 48 dp[i][j] = INF; 49 for(int p = i - 1; p < j; ++p){ 50 if(dp[i - 1][p] + dis[p + 1][j] < dp[i][j]){ 51 dp[i][j] = dp[i - 1][p] + dis[p + 1][j]; 52 path[i][j] = p; 53 } 54 } 55 } 56 } 57 printf("Chain %d\n",++Case); 58 cnt = 0; 59 Print(k,n); 60 printf("Total distance sum = %d\n\n",dp[k][n]); 61 } 62 return 0; 63 }