码迷,mamicode.com
首页 > 其他好文 > 详细

poj1160

时间:2018-11-08 00:21:24      阅读:189      评论:0      收藏:0      [点我收藏+]

标签:http   one   作用   数组   区间dp   cst   article   std   一点   

题意如下:在一条水平的公路上建有n个小屋,两个小屋间的距离是它们的横坐标之差的绝对值。保证小屋的横坐标是整数,以及没有两个小屋建立在同一位置。现在需要建立m所加油站(m<=n),加油站只能建立在小屋所在的位置。 
现在需要你写个程序,给定了所有小屋的位置和加油站的数目,计算出每个小屋离最近的加油站的距离总和的最小值。 

 

我觉得这道题最重要的一点是要意识到一点,每个加油站是有它的所划分好的区域的,这样就可以进行区间dp了

 

第一行包括两个整数n和m: 1 <= n <= 300, 1 <= m <= 30, m <= n. 第二行包括n个整数,代表小屋的位置,以升序的形式列出。对于每一个整数x,1 <= X <= 10000.

 

这道题我开始的想法没想到先预处理,我一开始先设状态为dp[n][m],然后转移设成dp[n][m]=min(dp[n-1][m-1],dp[n-1][m]),发现这个转移根本转移不下,然后就自闭了,这样错误的原因是什么呢?我没有搞懂它的作用域

接下来我引用一段话这是这个人的博客:https://blog.csdn.net/ccdllyy/article/details/78087848

思路:典型的DP问题。

当我们在v个村庄中只建一个邮局,可以推导出,只有邮局位于中间位置,距离和才最小;有一个特殊情况是,当村庄数为偶数,中间位置有两个村庄,经过计算,两个村庄的距离和相等,所以俩位置均可。

可以联想到,N个村庄建P个邮局,相当于每个邮局均有一个作用范围,该邮局位于其作用范围的中间位置,就是要找到一个k,使前k个村庄建P - 1个邮局,最后几个村庄建一个邮局的方案满足题意。

那么,状态转移方程就可以写成:

dp[i][j]:前i个村庄建j个邮局的最小距离和

dis[i][j]:第i个村庄到第j个村庄之间建1个邮局的最小距离和

状态转移方程:dp[i][j] = min(dp[i][j],dp[k][j - 1] + dis[k + 1][j])

还有一点,计算dis[i][j]时,dis[i][j - 1]已经计算出来,而且可以推导出无论j - 1为奇数还是偶数,dis[i][j]均可以写成dis[i][j - 1] + j距离i、j中点的距离。

 

那么接下来就不难了,但是我又wa了很多发,原因是数组开小了

技术分享图片
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<iostream>
 5 #define inf 0X3f3f3f3f
 6 using namespace std;
 7 int n,m;
 8 int num[350];
 9 int dp[350][350];
10 int dis[350][350];
11 int main(){
12     while(scanf("%d%d",&n,&m)!=EOF){
13         for(int i=1;i<=n;i++) scanf("%d",&num[i]);
14         memset(dis,0,sizeof(dis));
15         for(int i=1;i<=n-1;i++){
16             for(int j=i+1;j<=n;j++){
17                 dis[i][j]=dis[i][j-1]+num[j]-num[(i+j)/2];
18             }
19         }
20         memset(dp, inf, sizeof(dp));
21         for(int i=1;i<=n;i++) dp[i][1]=dis[1][i];
22         for(int i=2;i<=m;i++){
23             for(int j=i;j<=n;j++){
24                 for(int k=i-1;k<=j-1;k++){
25                     dp[j][i]=min(dp[j][i],dp[k][i-1]+dis[k+1][j]);
26                 }
27             }
28         }
29         printf("%d\n",dp[n][m]);
30     }
31     return 0;
32 }
View Code

 

poj1160

标签:http   one   作用   数组   区间dp   cst   article   std   一点   

原文地址:https://www.cnblogs.com/pandaking/p/9926535.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!