链接http://poj.org/problem?id=1160

很好的一个题,涉及到了以前老师说过的一个题目,可惜没往那上面想。

题意,给出N个城镇的地址,他们在一条直线上,现在要选择P个城镇建立邮局,使得每个城镇到离他最近的邮局距离的总和尽量小。

首先提一个这个问题的简化版本,如果P=1得话,这个距离是多少呢? 这个问题的解就是将这个唯一的邮局建在(l+r)/2的位置,答案就是最优解,

这个类似于中位数的概念,我们有一个数学归纳法简单的证明

数轴上有n个点,求到这n个点距离最小的一个点   问题描述:如题分析:这个题目不能简单地将所有点的平均数作为答案,这样是不对的,有反例。例如:x1=1, x2=3, x3=4, x4=100, 那么他们的平均数为x=27, 所有点到x的距离为146, 但当我们取x=10时,得打距离的值为116,比146更小。下面我们来用归纳法的思想来分析:如果n=1,那么就取这个点如果n=2,那么取x1和x2之间的任何一个点都是答案如果n=3,那么取中间的那个点,就是答案如果n=4,那么取中间的两个点所构成的闭区间就是答案... 如果n是奇数,那么就是第(n+1)/2这个点如果n是偶数,那么就是n/2这个点和(n/2)+1这两个点所构成的闭区间假设所有点都按序排列。
  同理也可以推广到二维平面选点,只要找两次x和y的中位数就是最佳的地址。

对于此题不难想到dp[i][j]表示前i个城镇建立j个邮局的最小花费距离,因为不是每个地方都有邮局所以用dp[i][j]表示i-j之间的话不太方便,起点总是1所以可以免去一维。

则 dp[i][j]=MIN{dp[i][j],dp[k][j-1]+dis[k+1][i]| ,1<=k<=i} 其中dis[a][b]表示a-b之间建立一个邮局的最小花费距离,由上面的方法可以引出递推式:dis[i][j]=dis[i][j-1]+x[j]-x[(i+j)/2]

一开始我卡住,因为想不通递推式,我想这个分割点k如果k后面的邮局选址会影响到前面某个点使得价值更低这样岂不是会计算错误吗,后来想了想发现,这样会使结果变大,但是总会循环到那个最优的k使得恰好互不影响。因为离某个城镇的邮局最近的地方只有两种情况,左边或者右边,如果到k时出现交叉即

i_______k______j,从k分割时,(k,j]之间建立的那个邮局使得[i,k]的某个点会有更小的距离。一直向右循环总会到达使得两边互不影响的点,此时计算得到最优解。

 #include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
int dp[][];
int x[],one[][]={};
int main()
{
int N,M,i,j,k;
// freopen("in.txt","r",stdin);
while(cin>>N>>M){
scanf("%d",&x[]);
for(i=;i<=N;++i)
scanf("%d",&x[i]);
memset(dp,inf,sizeof(dp));
for(i=;i<=N;++i)
for(j=i;j<=N;++j)
if(i==j) one[i][i]=;
else
one[i][j]=one[i][j-]+x[j]-x[(i+j)/];
for(i=;i<=N;++i) dp[i][]=one[][i];
for(i=;i<=N;++i)
{
int up=min(M,i);
for(j=;j<=up;++j)
{
for(k=;k<=i;++k)
{
int s=dp[k][j-]+one[k+][i];
if(dp[i][j]>s) dp[i][j]=s;
}
}
}
printf("%d\n",dp[N][M]);
}
return ;
}

上面的渐进复杂度是O(N^2*M),对于此题的数据来说不必优化也能AC,但我们还是想这个可以利用四边形不等式优化吗?

在集训队毛子青的那篇<动态规划演算法的优化技巧>中明确指出,这道题目是可以的,我们在比赛时时没时间去证明也可以写一个朴素法来对拍。

这个题目不同于我们常见的区间dp,常见的区间dp是由小区间推导大区间,所以在计算dp[i][j]时,s[i][j-1]、s[i+1][j]都是[i,j]的子区间,在之前就计算出来了,

但是这个题目我们用dp[i][j]表示的区间是[1,i],在推导dp[i][j]时,s[i+1][j]还是未知的,我看了许多人写的博客都是将j倒置处理然后对s[i+1][j]附一个初值,我很不解为何非要这样,难道正方向推导不可行吗,研究了半天猜得出以上结论,他们那样处理就是因为不知道上界,所以将上界赋值为最大,知道了问题所在就简单了。

我们既然不知道s[i+1][j]只要令s[i+1][j]=i+1不就好了吗,下界得话我们已知,即使这样也能减小一些复杂度。

要时刻记住每个数组表示的意义才能准确的推导,s[i][j]表示的是k的范围所以最差情况就是[1,i];

 #include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
int dp[][];
int x[],one[][]={};
int K[][];
int main()
{
int N,M,i,j,k;
// freopen("in.txt","r",stdin);
while(cin>>N>>M){
for(i=;i<=N;++i) scanf("%d",&x[i]);
memset(dp,inf,sizeof(dp));
for(i=;i<=N;++i)
for(j=i;j<=N;++j)
if(i==j) one[i][i]=;
else
one[i][j]=one[i][j-]+x[j]-x[(i+j)/];
for(i=;i<=N;++i) dp[i][]=one[][i];
for(i=;i<=N;++i) K[i][i]=;
for(j=;j<=M;++j)
{
for(i=;i<=N;++i)
{
K[i+][j]=i+;
if(j>i) continue;
for(k=K[i][j-];k<=K[i+][j];++k)
{
int s=dp[k][j-]+one[k+][i];
if(dp[i][j]>s) {
dp[i][j]=s;
K[i][j]=k;
}
}
}
}
printf("%d\n",dp[N][M]);
}
return ;
}

POJ 1160 经典区间dp/四边形优化的更多相关文章

  1. 51Nod 1022 石子归并 V2(区间DP+四边形优化)

    题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1022 题目大意: N堆石子摆成一个环.现要将石子有次序地合并成 ...

  2. HDU 3506 (环形石子合并)区间dp+四边形优化

    Monkey Party Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)Tot ...

  3. POJ.1160.Post Office(DP 四边形不等式)

    题目链接 \(Description\) 一条直线上有n个村庄,位置各不相同.选择p个村庄建邮局,求每个村庄到最近邮局的距离之和的最小值. \(Solution\) 先考虑在\([l,r]\)建一个邮 ...

  4. hdu3516 Tree Construction (区间dp+四边形优化)

    构造方法肯定是把相邻两个点连到一起,变成一个新点,然后再把新点和别的点连到一起.... 设f[i,j]为把第i到j个点都连到一起的代价,那么答案就是f[1,n] f[i,j]=min{f[i,k]+f ...

  5. 区间dp+四边形不等式优化

    区间dp+四边形优化 luogu:p2858 题意 给出一列数 \(v_i\),每天只能取两端的数,第 j 天取数价值为\(v_i \times j\),最大价值?? 转移方程 dp[i][j] :n ...

  6. CSP 201612-4 压缩编码 【区间DP+四边形不等式优化】

    问题描述 试题编号: 201612-4 试题名称: 压缩编码 时间限制: 3.0s 内存限制: 256.0MB 问题描述: 问题描述 给定一段文字,已知单词a1, a2, …, an出现的频率分别t1 ...

  7. HDU3480_区间DP平行四边形优化

    HDU3480_区间DP平行四边形优化 做到现在能一眼看出来是区间DP的问题了 也能够知道dp[i][j]表示前  i  个节点被分为  j  个区间所取得的最优值的情况 cost[i][j]表示从i ...

  8. POJ 2995 Brackets 区间DP

    POJ 2995 Brackets 区间DP 题意 大意:给你一个字符串,询问这个字符串满足要求的有多少,()和[]都是一个匹配.需要注意的是这里的匹配规则. 解题思路 区间DP,开始自己没想到是区间 ...

  9. hdu 3506 Monkey Party 区间dp + 四边形不等式优化

    http://acm.hdu.edu.cn/showproblem.php?pid=3506 四边行不等式:http://baike.baidu.com/link?url=lHOFq_58V-Qpz_ ...

随机推荐

  1. mac下python环境pip报错[SSL: TLSV1_ALERT_PROTOCOL_VERSION] tlsv1 alert protocol version (_ssl.c:590) 的解决方法

    1.mac下python环境pip报错: issuserdeMacBook-Pro:~ issuser$ pip install pyinstallerCollecting pyinstaller  ...

  2. 手把手教 GitHub + Hexo 搭建博客

    前言 在很久以前,博主就想着要有自主的博客专栏或者网站.经历了博客园这个需要所谓的编辑审核,一直比较困惑,这些编辑是什么出身,怎么知道技术博客的价值性. 接下来找到了开源中国,这个可以自由发言的地方. ...

  3. mysql锁机制之间隙锁(Next-Key锁)(五)

    间隙锁(Next-Key锁) 当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的 索引项加锁:对于键值在条件范围内但并不存在的记录,叫做“间隙(GA ...

  4. [HZNUOJ] 使用Excel + Word 批量制作准考证

    一般程序设计考试或者ACM比赛都会使用临时账号登录,这时候就需要批量制作密码条 首先需要用Excel 存储队伍的信息 比如像这样分门别类的放好 然后在word 中制作好密码条样式 选择邮件->开 ...

  5. 2016-2017 National Taiwan University World Final Team Selection Contest J - Zero Game

    题目: You are given one string S consisting of only '0' and '1'. You are bored, so you start to play w ...

  6. springer论文模板参考文献的顺序问题

    latex环境 MikTex 2.9 + TeXstudio 2.12.8 (+ Mendeley) 问题 springer提供的latex模板 中最后的参考文献是按照字母顺序排列的.我想要弄成按照文 ...

  7. datanode扩容步骤

    新扩容机器规划: hostname ip 进程 slave3 10.183.225.167 datanode,nodemange 1. 修改/etc/hosts 增加新扩容机器的hostname 10 ...

  8. 学号20145322 《Java程序设计》第一周学习总结

    学号20145322 <Java程序设计>第一周学习总结 教材学习内容总结 Java诞生于Sun公司,于1998年12月4日发布J2SE,约以两年为一周期推出重大版本更新. 2010年Or ...

  9. C++开学第一次作业(5.4)

    开学第一次作业(5.4) 代码传送门 题目 Create a program that asks for the radius of a circle and prints the area of t ...

  10. JAVA启动参数整理[转]

    java启动参数共分为三类: 其一是标准参数(-),所有的JVM实现都必须实现这些参数的功能,而且向后兼容: 其二是非标准参数(-X),默认jvm实现这些参数的功能,但是并不保证所有jvm实现都满足, ...