您的位置:首页 > 其它

poj 1160

2015-01-04 21:01 274 查看
题意为给出n个村庄的坐标,问如何设立m个邮局,使得每个村庄离其最近邮局的总路程即总花费最小。

思路:

若只设立一个邮局,可知邮局设在村庄坐标中位数的位置是最优解。这个问题属于在n个东西中选出m个,求全局最优解的问题。自然想到dp。设立二维数组dp[i][j-1]表示i个邮局放入前j个村庄所需的最小费用。可得dp方程:dp[i][j]=min(dp[i-1][k]+cost[k+1][j]) (i-1<=k<j)。cost[i][j]表示在村庄i到村庄j之间选一个村庄设立邮局的最小花费,即为村庄[i,j]中每个村庄到ij中位数村庄的距离和,可预处理得到.。转移方程的意义上是:枚举前i-1个邮局所占有的村庄区间,即为0到k,剩余的一个邮局在区间k+1到j,其最小花费为cost[i][j]。所有k种组合的最小值即为dp[i][j]的值。

cost 数组求解的过程中也存在一个递推式:cost[i][j]=cost[i][j-1]+vl[j]-vl[(i+j)/2],其中vl[i]表示第i+1个村庄的坐标。纸上画一画可知其正确性。

注意:dp[1][j]=cost[0][j]的初始化

#include <cstdio>
using namespace std;
int dp[31][301];
int cost[301][301];
int vl[301];
int v,p;
int main()
{
	scanf("%d%d",&v,&p);
	for(int i=0;i<v;i++)
		scanf("%d",vl+i);
	for(int i = 0; i < v-1; ++i)
		for(int j=i+1;j<v;++j)
			cost[i][j]=cost[i][j-1]+vl[j]-vl[(i+j)/2];//预处理得到cost数组的值
	for(int i=1;i<v;i++)
		dp[1][i]=cost[0][i];//dp初始化
	for(int i=2;i<=p;i++)
		for(int j=i;j<v;j++)
		{
			int t=dp[i-1][i-1]+cost[i][j];
			for(int k=i;k<j;k++)
				if(dp[i-1][k]+cost[k+1][j]<t)
					t=dp[i-1][k]+cost[k+1][j];
			dp[i][j]=t;
		}
	printf("%d\n",dp[p][v-1]);
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: