题目链接: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\n",dp[n][m]); 33 } 34 return 0; 35 }
时间: 2024-10-05 05:11:10