1. 程式人生 > >I - Post Office POJ - 1160 (動態規劃)

I - Post Office POJ - 1160 (動態規劃)

I - Post Office

 POJ - 1160 

There is a straight highway with villages alongside the highway. The highway is represented as an integer axis, and the position of each village is identified with a single integer coordinate. There are no two villages in the same position. The distance between two positions is the absolute value of the difference of their integer coordinates. 

Post offices will be built in some, but not necessarily all of the villages. A village and the post office in it have the same position. For building the post offices, their positions should be chosen so that the total sum of all distances between each village and its nearest post office is minimum. 

You are to write a program which, given the positions of the villages and the number of post offices, computes the least possible sum of all distances between each village and its nearest post office. 

Input

Your program is to read from standard input. The first line contains two integers: the first is the number of villages V, 1 <= V <= 300, and the second is the number of post offices P, 1 <= P <= 30, P <= V. The second line contains V integers in increasing order. These V integers are the positions of the villages. For each position X it holds that 1 <= X <= 10000.

Output

The first line contains one integer S, which is the sum of all distances between each village and its nearest post office.

Sample Input

10 5
1 2 3 6 7 9 11 22 44 50

Sample Output

9

 dp[x][num]表示從開始到x位置建立num個郵局的總耗費,動態規劃講究從已知子問題結果中尋找答案,那麼容易想到從建立一個郵局到p個問題的解題過程,假設當前建立i個郵局,而前面到位置j(j>=i-1&&j<=n)建立i-1個郵局的最優解已經得到,那麼求到位置j建立i個郵局的問題就轉換為在j位置前找一個位置k(k>=i&&k<=j),讓[k,j]作為建立第j個郵局的作用域(即[k,j]到第j個郵局最近),使在位置j前建立i個郵局有最優解。

於是有狀態轉換方程:

dp[j][i]=min{dp[k-1][i-1]+sum[k][j]}  //在位置j前建立i個郵局

求sum陣列的優化問題,參考了網上的解析:可以假定有6個村莊,村莊的座標已知分別為p1,p2,p3,p4,p5,p6;那麼,如果要求sum[1][4]的話郵局需要建立在2或者3處,放在2處的消耗為p4-p2+p3-p2+p2-p1=p4-p2+p3-p1
放在3處的結果為p4-p3+p3-p2+p3-p1=p4+p3-p2-p1,可見,將郵局建在2處或3處是一樣的。現在接著求sum[1][5],現在處於中點的村莊是3,那麼1-4到3的距離和剛才已經求出了,即為sum[1][4],所以只需再加上5到3的距離即可。同樣,求sum[1][6]的時候也可以用sum[1][5]加上6到中點的距離。所以有遞推關係:sum[i][j] = sum[i][j-1] + p[j] -p[(i+j)/2]

#include<cstdio>
#include<stack>
#include<set>
#include<vector>
#include<queue>
#include<algorithm>
#include<cstring>
#include<string>
#include<map>
#include<iostream>
#include<cmath>
using namespace std;
#define inf 0x3f3f3f3f
typedef long long ll;
const int N=330;
const double esp = 1e-9;
const double PI=3.1415926;
int dp[N][N],sum[N][N],a[N];
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF){
      for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
      memset(sum,0,sizeof(sum));
      for(int i=1;i<n;i++){
            for(int j=i+1;j<=n;j++){
                  sum[i][j]=sum[i][j-1]+a[j]-a[(i+j)/2];
            }
      }
      memset(dp,inf,sizeof(dp));
      for(int i=1;i<=n;i++)
            dp[i][1]=sum[1][i];
      for(int i=2;i<=m;i++){
            for(int j=i;j<=n;j++){
                  for(int k=i;k<=j;k++)
                        dp[j][i]=min(dp[j][i],dp[k-1][i-1]+sum[k][j]);
            }
      }
      printf("%d\n",dp[n][m]);
    }
    return 0;
}