POJ 1160 Post Office(DP+经典预处理)

题目链接:http://poj.org/problem?id=1160

题目大意:在v个村庄中建立p个邮局,求所有村庄到它最近的邮局的距离和,村庄在一条直线上,邮局建在村庄上。

解题思路:设dp[i][j]表示到第i个村庄为止建立j个邮局的最小距离和,dis[i][j]表示i~j之间建一个邮局的最小距离和,我们很容易得出状态转移方程:dp[i][j]=min{dp[k][j]+dis[k+1][i]}(k<i)。

     主要是dis[i][j]的预处理很巧妙,从别人的博客上看的“将邮局建在i~j中间即(i+j)/2的位置,如果i+j不能被整除建在左边和右边结果一样”。于是dis[i][j]=dis[i][j-1]+pos[j]-pos[(i+j)/2]。

代码:

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 using namespace std;
 5 const int N=1e3+5;
 6 
 7 int dp[N][50],pos[N],dis[N][N];//dis[i][j]表示在i~j之间建一个邮局的最小距离和 
 8 
 9 int main(){
10     int n,m;
11     while(~scanf("%d%d",&n,&m)){
12         memset(dp,0x3f,sizeof(dp));
13         for(int i=1;i<=n;i++){
14             scanf("%d",&pos[i]);
15         }
16         //预处理dis[i][j]
17         for(int i=1;i<=n;i++){
18             dis[i][i]=0;
19             for(int j=i+1;j<=n;j++){
20                 dis[i][j]=dis[i][j-1]+pos[j]-pos[(i+j)/2];
21             }
22             dp[i][1]=dis[1][i];
23         }
24         
25         for(int j=2;j<=m;j++){
26             for(int i=j;i<=n;i++){
27                 for(int k=j-1;k<i;k++){
28                     dp[i][j]=min(dp[k][j-1]+dis[k+1][i],dp[i][j]);
29                 }
30             }
31         }
32         printf("%d
",dp[n][m]);
33     }
34     return 0;
35 }
原文地址:https://www.cnblogs.com/fu3638/p/7827702.html