题目大意:有V个村庄,要求在V个村庄中建立P个邮局,要求其他村庄到离它最近的村庄的距离之和最小。
算法思想:
DP
1.当有N个乡村和一个邮局的时候,邮局建在村庄的中点时,距离之和最小。
2.普及到一半情况,有i个村庄j个邮局,则用j-1个邮局覆盖前r个村庄,用第j个村庄覆盖第r+1到i个邮局.则递归方乘如下:
dp[i][j]=min{dp[i][j],dp[r][j-1]+sum[r+1][i]} (j-1<r<i)
3.距离优化.sum[a][b]=sum[a][b-1]+x[b]-x[(a+b)/2] ................................画图带个特例就明白了
代码如下:
#include <iostream>
#include <cstring>
#include <climits>
#include <algorithm>
using namespace std;
int DP[305][35];
int sum[305][305];
int main(){
int v,p;
int x[305];
cin>>v>>p;
for(int i=1;i<=v;i++){
cin>>x[i];
}// 输入村庄的位置坐标
memset(DP,0,sizeof(DP));
//memset(sum,0,sizeof(sum));
for(int i=1;i<=v;i++){//优化策略
for(int j=i+1;j<=v;j++){
sum[i][j]=sum[i][j-1]+x[j]-x[(i+j)/2];
}
}
for(int i=1;i<=v;i++){
DP[i][i]=0;//村庄数与邮局数相同
DP[i][1]=sum[1][i];
}
for(int j=2;j<=p;j++){//枚举邮局的数量,邮局数量为1的时候已近计算过了
for(int i=j+1;i<=v;i++){//枚举乡村的数量
DP[i][j]=INT_MAX;
for(int k=j-1;k<i;k++){//找出每对 i,j 时的最小距离之和 j-1<k<i......key.....!
DP[i][j]=min(DP[i][j],DP[k][j-1]+sum[k+1][i]);//此处用到了一种迭代寻找最小值
}
}
}
cout<<DP[v][p]<<endl;
return 0;
}