pku1160postoffice邮局分布问题结题报告

经典问题。最主要的是要用每个邮局的分布进行动态规划,即由求每一个邮局在所有城镇中的的最小值,让后依次类推,再求第二个,第三个。。。最后得到答案。。

题目给出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.csdn.net/china8848/archive/2008/01/12/2039670.aspx

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值