POJ 1160 Post Office

来源:互联网 发布:手机学钢琴软件 编辑:程序博客网 时间:2024/06/05 17:16

题意:一条公路上有n个村庄,现在需要建造m个邮局,问邮局建造后使得所有的村庄到对应的邮局的路程总和的最小值。

思路:很水的,先自己推一下,i个村庄到j个村庄里建一个邮局,邮局所建的位置由决定于i到j之间的村庄的数量   ,如果数量为奇数的话   直接处于最中间的点,如果为偶数的话,处于最中间的2个点之间。(鉴于你不在我身边,证明略,提示一下,一层层去最外面的2个村庄)。

dis[i][j]表示i村庄到j村庄之间建个邮局,最小的路程总和。

dp[i][j]表示的是建第i个邮局,起作用的终点为第j个村庄。

状态转移方程:(邮局建立的顺序是依次建的)

                  for(int e=i;e<j;++e)
               dp[i][j] = min(dp[i][j],dp[i-1][e]+dis[e+1][j]);

#include<cstdio>#include<cstring>#include<iostream>#define INF 0x3f3f3f3f#define min(a1,b1) (a1)>(b1)?(b1):(a1)using namespace std;int n,m;int arr[310];int dp[31][301];int dis[310][310];void ini(){     for(int i=1;i<=n;++i)         dis[i][i] = 0;      for(int i=1;i<n;++i)        dis[i][i+1] = arr[i+1] - arr[i];      for(int i=2;i<n;++i)      {        for(int j=1;j+i<=n;++j)         {             int ent = j+i;           dis[j][ent] = arr[ent] - arr[j] + dis[j+1][ent-1];         }      }}int main(void){    while(cin>>n>>m)    {      memset(dp,0,sizeof(dp));      for(int i=1;i<=n;++i)      scanf("%d",&arr[i]);      ini();      memset(dp,0,sizeof(dp));      for(int i=1;i<=n;++i)      dp[1][i] = dis[1][i];      for(int i=2;i<=m;++i)      {       for(int j=i;j<=n;++j)       {           dp[i][j] = INF;           if(j==i)           {             dp[i][j] = 0;           }           else           {               for(int e=i;e<j;++e)               dp[i][j] = min(dp[i][j],dp[i-1][e]+dis[e+1][j]);           }       }      }      cout<<dp[m][n]<<endl;    }    return 0;}