POJ 1160 邮局
状态:dp[i][j] 表示前j个村庄覆盖i个邮局所用最小值。
cost[j+1][j+k]表示j+1..j+k个村庄覆盖一个邮局的最小值。
其中j>=1
转移方程:dp[i+1][j+k]=min(dp[i-1][j]+cost[j+1][j+k]) 其中 j>=1;
#include<stdio.h>
#include <string.h>
int cost[302][302];
int dp[302][302];
int v[302];
int kabs(int a)
{
return a>0?a:-a;
}
int main(){
int V,P,mid;
int tcase;
scanf("%d",&tcase);
while(tcase--){
scanf("%d %d",&V,&P);
for (int i=1;i<=V;i++)
scanf("%d",v+i);
//cost[i][j] 表示从i到j构建一个邮局距离之和
memset(dp,0,sizeof(dp));
memset(cost,0,sizeof(cost));
for (int i=1;i<=V;i++){
for (int j=i;j<=V;j++){
mid=(i+j)>>1;//中位数 奇数时取中间的 偶数时取中间两个前者
for (int k=i;k<=j;k++)
cost[i][j] +=kabs(v[mid]-v[k]);
}
}
//dp[i][j] 表示前i个邮局覆盖前j个村庄的最小代价
for (int i=1;i<=V;i++)
dp[1][i]=cost[1][i];
for (int i=2;i<=P;i++){
for (int j=1;j<=V;j++){
for (int k=1;k+j<=V;k++){
if(dp[i][j+k]>dp[i-1][j]+cost[j+1][j+k] || dp[i][j+k]==0)//update
dp[i][j+k]=dp[i-1][j]+cost[j+1][j+k];
}
}
}
printf("%d\n",dp[P][V]);
}
return 0;
}注:本以为可以剪去部分内容,自己强加了一个条件,J>=I
但是提交后错误,因为多个邮局可以建在一个村庄。

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



