pku1160
DP .首先求出任意两个村庄间(包括端点)建一个邮局后,到邮局的最短距离和,记为min_dis[i][j],当邮局建到中点时min_dis[i][j]最小. 用f[i][j]表示前i个邮局建在前j个村庄.则f[i][j]=min{f[i-1][k]+min_dis[k+1][j],i-1<=k<j}.见代码:
#include
<
iostream
>
using namespace std;
int v,p;
int vill[ 305 ];
int f[ 35 ][ 305 ];
int min_dis[ 305 ][ 305 ];
int main()
{
int i,j,k;
scanf("%d%d",&v,&p);
for(i=1;i<=v;i++)
scanf("%d",&vill[i]);
memset(min_dis,0,sizeof(min_dis));
for(i=1;i<=v;i++)
for(j=i+1;j<=v;j++)
{
int mid=(i+j)/2;
for(k=i;k<mid;k++)
{
min_dis[i][j]+=vill[mid]-vill[k];
}
for(k=mid+1;k<=j;k++)
{
min_dis[i][j]+=vill[k]-vill[mid];
}
}
for(i=1;i<=v;i++) f[1][i]=min_dis[1][i];
for(i=2;i<=p;i++)
for(j=i;j<=v;j++)
{
int minn=100000000;
for(k=i-1;k<=j-1;k++)
{
if(f[i-1][k]+min_dis[k+1][j]<minn)
minn=f[i-1][k]+min_dis[k+1][j];
}
f[i][j]=minn;
}
printf("%d\n",f[p][v]);
//system("pause");
return 0;
}
using namespace std;
int v,p;
int vill[ 305 ];
int f[ 35 ][ 305 ];
int min_dis[ 305 ][ 305 ];
int main()
{
int i,j,k;
scanf("%d%d",&v,&p);
for(i=1;i<=v;i++)
scanf("%d",&vill[i]);
memset(min_dis,0,sizeof(min_dis));
for(i=1;i<=v;i++)
for(j=i+1;j<=v;j++)
{
int mid=(i+j)/2;
for(k=i;k<mid;k++)
{
min_dis[i][j]+=vill[mid]-vill[k];
}
for(k=mid+1;k<=j;k++)
{
min_dis[i][j]+=vill[k]-vill[mid];
}
}
for(i=1;i<=v;i++) f[1][i]=min_dis[1][i];
for(i=2;i<=p;i++)
for(j=i;j<=v;j++)
{
int minn=100000000;
for(k=i-1;k<=j-1;k++)
{
if(f[i-1][k]+min_dis[k+1][j]<minn)
minn=f[i-1][k]+min_dis[k+1][j];
}
f[i][j]=minn;
}
printf("%d\n",f[p][v]);
//system("pause");
return 0;
}