经典问题。最主要的是要用每个邮局的分布进行动态规划,即由求每一个邮局在所有城镇中的的最小值,让后依次类推,再求第二个,第三个。。。最后得到答案。。
题目给出m个村庄及其距离,给出n个邮局,要求怎么建n个邮局使代价最小。思路:用opt[i][j]记录把前i个邮局建到前j个村庄中的最优解,用cost[i][j]记录所有在i到j村庄中,建1个邮局的最小代价。显然邮局应该设到中点(很重要)。让前i个邮局覆盖前j个村庄,第i+1个邮局覆盖第j+1至j+k个村庄(j+k<=n),则状态转移方程为
opt[i+1][j+k]=min{opt[i][j]+cost[j+1][j+k];} (k+j<=n)
Cost数组存放从i到j中有一个邮局的最小代价,显然该邮局应该放在中间,构造cost的代码和结果如下:
for(i=1;i<=m;i++)
for(j=i;j<=m;j++)
{
cost[i][j] = 0;
mid = (i+j)/2;
for(k=i;k<=j;k++)
cost[i][j]+=(distance[mid]-distance[k])>=0 ?
distance[mid]-distance[k]:distance[k]-distance[mid];
}
Opt[i][j] 表示前i个邮局覆盖前j个村庄的最小代价,对于i=1来说,opt[i][j] = cost[i][j],让前2个邮局覆盖前j个村庄,也就是i=2的情况,可能是一下情况的最优解:第一个邮局覆盖第一个村庄,第二个村庄覆盖2-j个村庄,或者第一个邮局覆盖第1-2个村庄,第二个村庄覆盖3-j个村庄,第一个邮局覆盖第1-3个村庄,第二个村庄覆盖4-j个村庄,等等等等。该部分的代码如下:
for(i=0;i<=n;i++)
for(j=0;j<=m;j++)
if(opt[i][j]<3000000)
{
for(k=1;j+k<=m;k++)
{
if(opt[i+1][j+k]>opt[i][j]+cost[j+1][j+k])
{
opt[i+1][j+k] = opt[i][j]+cost[j+1][j+k];//求每个邮局在j+1到j+k上的最小值。。。
}
}
}
最后的opt[m][n]就是结果。。。
代码为
:
#include<stdio.h>
#define maxi 30000000
void main(){
int i,n,j,m,k,mid;
int opt[35][310],cost[310][310],t[301];
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
scanf("%d",&t[i]);
for(i=1;i<=n;i++)
for(j=i;j<=n;j++){
cost[i][j]=0;
mid=(i+j)/2;
for(k=i;k<=mid;k++)
cost[i][j]+=t[mid]-t[k];
for(k=mid+1;k<=j;k++)
cost[i][j]+=(t[k]-t[mid]);
}
for(i=0;i<=m;i++)
for(j=0;j<=n;j++)
opt[i][j]=maxi;
opt[0][0]=0;
for(i=0;i<=m;i++)
for(j=0;j<=n;j++)
if(opt[i][j]<maxi){
for(k=1;k+j<=n;k++)
if(opt[i+1][j+k]>opt[i][j]+cost[j+1][j+k])
opt[i+1][j+k]=opt[i][j]+cost[j+1][j+k];
}
printf("%d/n",opt[m][n]);
}原解题报告链接:http://blog.youkuaiyun.com/china8848/archive/2008/01/12/2039670.aspx