思路:设dp[i][j]为前j个地方放i个邮局且第i个放在地方j上的最小距离和。
那么dp[i][j] = min(dp[i][j],dp[i-1][k] +w(k,j)) (w(k,j)为区间k到j的最小距离和)
这里可以用四边形不等式优化。
我的代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 305;
int n,m,x[maxn],s[maxn][maxn];
int dp[maxn][maxn];
int main(){
while(~scanf("%d%d",&n,&m)){
for(int i=1;i<=n;i++) scanf("%d",&x[i]);
memset(s,0,sizeof(s));
memset(dp,63,sizeof(dp));
for(int i=n;i>0;i--){
for(int j=i+2;j<=n;j++){
for(int k=i+1;k<j;k++){
s[i][j] += min(x[j]-x[k],x[k]-x[i]);
}
}
}
for(int j=1;j<=n;j++){
dp[1][j] = 0;
for(int k=1;k<j;k++) dp[1][j] += x[j] - x[k];
}
for(int i=2;i<=m;i++){
for(int j=i;j<=n;j++){
for(int k = i-1;k<j;k++)
dp[i][j] = min(dp[i][j],dp[i-1][k]+s[k][j]);
}
}
int ans = 0x3f3f3f3f;
for(int i=m;i<=n;i++){
int tmp = dp[m][i];
for(int j=i+1;j<=n;j++) tmp += x[j] - x[i];
ans = min(ans,tmp);
}
printf("%d\n",ans);
}
return 0;
}