首先要知道一个定理就是在一个区间内如果要设置一个邮局的话,最优位置一定是最中间的村子,而且如果村子数是偶数的话,中间的两个点是等价的。
知道了这个之后,就可以N^2处理出来任一一个区间中只设置一个邮局的最小距离和。cost[i][j]表示区间村子i到村子j。
dp[i][j]表示前i个村庄中设置j个邮局之后的最小距离和。
那么转移就是dp[i][j]=min(dp[i-1][k]+cost[k+1][j]) (枚举k且k<j)
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int V,P;
int Abs(int n){
return n>0?n:(-n);
}
int dp[40][305];
int p[305];
int cost[305][305];
int Get(int i,int j){
int mid=(i+j)/2;
int sum=0;
for(int k=i;k<=j;k++){
sum+=Abs(p[k]-p[mid]);
}
return sum;
}
int main(){
while(~scanf("%d%d",&V,&P)){
memset(dp,0x3f,sizeof(dp));
for(int i=1;i<=V;i++){
scanf("%d",&p[i]);
}
for(int i=1;i<=V;i++){
for(int j=i;j<=V;j++){
cost[i][j]=Get(i,j);
//cout<<cost[i][j]<<endl;
}
}
for(int i=1;i<=V;i++){
dp[1][i]=cost[1][i];
}
for(int i=2;i<=P;i++){
for(int j=i;j<=V;j++){
for(int k=1;k<j;k++){
dp[i][j]=min(dp[i][j],dp[i-1][k]+cost[k+1][j]);
}
}
}
cout<<dp[P][V]<<endl;
}
return 0;
}
1422



被折叠的 条评论
为什么被折叠?



