热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

四边形不等式优化dp应用------pku1160postoffice解题报告

四边形不等式优化动态规划原理:1.当决策代价函数w[i][j]满足w[i][j]+w[i’][j’]<w[I;][j]+w[i][j’](i<i’<j<j’)

四边形不等式优化动态规划原理:

1.当决策代价函数w[i][j]满足w[i][j]+w[i’][j’]<=w[I;][j]+w[i][j’](i<=i’<=j<=j’),w满足四边形不等式.当函数w[i][j]满足w[i’][j]<=w[i][j’] i<=i’<=j<=j’),w关于区间包含关系单调.

2.如果状态转移方程m且决策代价w满足四边形不等式的单调函数(可以推导出m亦为满足四边形不等式的单调函数),则可利用四边形不等式推出最优决策s的单调函数性,从而减少每个状态的状态数,将算法的时间复杂度由原来的O(n^3)降低为O(n^2).方法是通过记录子区间的最优决策来减少当前的决策量.:

s[i][j]=max{k | ma[i][j] = m[i][k-1] + m[k][j] + w[i][j]}

由于决策s具有单调性,因此状态转移方程可修改为:

 

证明过程: (转载)

m[i,j]表示动态规划的状态量。

m[i,j]有类似如下的状态转移方程:

m[i,j]=opt{m[i,k]+m[k,j]}(ikj)

如果对于任意的abcd,有m[a,c]+m[b,d]m[a,d]+m[b,c],那么m[i,j]满足四边形不等式。

以上是适用这种优化方法的必要条件

对于一道具体的题目,我们首先要证明它满足这个条件,一般来说用数学归纳法证明,根据题目的不同而不同。

通常的动态规划的复杂度是O(n3),我们可以优化到O(n2)

s[i,j]m[i,j]的决策量,即m[i,j]=m[i,s[i,j]]+m[s[i,j]+j]

我们可以证明,s[i,j-1]s[i,j]s[i+1,j]  (证明过程见下)

那么改变状态转移方程为:

m[i,j]=opt{m[i,k]+m[k,j]}      (s[i,j-1]ks[i+1,j])

复杂度分析:不难看出,复杂度决定于s的值,以求m[i,i+L]为例,

(s[2,L+1]-s[1,L])+(s[3,L+2]-s[2,L+1])…+(s[n-L+1,n]-s[n-L,n-1])=s[n-L+1,n]-s[1,L]n

所以总复杂度是O(n2)

s[i,j-1]s[i,j]s[i+1,j]的证明:

mk[i,j]=m[i,k]+m[k,j]s[i,j]=d

对于任意k,有mk[i,j]md[i,j](这里以m[i,j]=min{m[i,k]+m[k,j]}为例,max的类似),接下来只要证明mk[i+1,j]md[i+1,j],那么只有当s[i+1,j]s[i,j]时才有可能有ms[i+1,j][i+1,j]md[i+1,j]

(mk[i+1,j]-md[i+1,j]) - (mk[i,j]-md[i,j])

=(mk[i+1,j]+md[i,j]) - (md[i+1,j]+mk[i,j])

=(m[i+1,k]+m[k,j]+m[i,d]+m[d,j]) - (m[i+1,d]+m[d,j]+m[i,k]+m[k,j])

=(m[i+1,k]+m[i,d]) - (m[i+1,d]+m[i,k])

m满足四边形不等式,∴对于ikm[i+1,k]+m[i,d]m[i+1,d]+m[i,k]

(mk[i+1,j]-md[i+1,j])(mk[i,j]-md[i,j])0

s[i,j]s[i+1,j],同理可证s[i,j-1]s[i,j]

证毕

扩展:

以上所给出的状态转移方程只是一种比较一般的,其实,很多状态转移方程都满足四边形不等式优化的条件。

解决这类问题的大概步骤是:

0.证明w满足四边形不等式,这里wm的附属量,形如m[i,j]=opt{m[i,k]+m[k,j]+w[i,j]},此时大多要先证明w满足条件才能进一步证明m满足条件

1.证明m满足四边形不等式

2.证明s[i,j-1]s[i,j]s[i+1,j]

 

pku 1160 Post Office 解题报告

题意: 给出m个村庄及其距离,给出n个邮局,要求怎么建n个邮局使代价最小.

 

算法:很显然用到动态规划,那么假设:

d[i…n],各邮局的坐标

w[i][j]表示在d[i][j]之间建立一个邮局的村庄为k,kij之和的一半(很显然在中间建一个邮局距离最小),那么

m[i][j]为在前j个村庄建立i个邮局的最小距离和.

那么状态转移方程为:

边界条件: m[1][j]=w[1][j]  (1<=j<=m)

状态转移方程:

那么思路则为:

for i=2 to p do      //递推邮局数

{

     //m:在前j个村庄建立i个邮局的最小距离和

     for j=n dwonto i+1 do    //按递减顺序枚举尾指针

     m[i][j]=inf;

     for k=1 to n do

     {

          temp = m[i-1][k]+calcw(k+1,j);

          if(temp

     }

}

这样时间复杂度显然为O(n^3),这是不能接受的. 

仔细分析这dp算法,关键是决策变量k枚举数太多, 联系到四边形不等式原理,w[i][j]m[i][j]很明显符合四边形不等式,我们假设决策变量s[i][j],如果在110的村庄中,建立1个邮局的最佳位置为8,那么在决定见多一个邮局的话,当然是在18之间了(根据四边形不等式原理猜想到),所以就在dp的过程中,s[i][j]记录前i-1个邮局的村庄数. 那么我们第三次搜索的时候,就需要根据决策表s[i-1][j]<=k<=s[i][j+1]的范围内枚举.而可以证明s[i][j]具有单调性,那么我们就可以利用s[i][j]单调性限制了上下界然后把 O(n^3)弄成了 O(n^2) 

sample为例:

状态方程m:

 

决策表s:

 

 

那么状态转移方程为:

边界条件: m[1][j]=w[1][j]  (1<=j<=m)

 

 

边界条件: m[1][j]=w[1][j]  (1<=j<=m)

状态转移方程:

决策记录表: s[i][j]=k

AC代码:

#include

#include

#include

#include

#define M 305                 //村庄数的上限

#define inf 1000000000        //无穷大

                                                   

long coordinate[M];           //每个村庄的x坐标

long dp[M][M];                //dp[i][j]表在在前j个村庄建立i个邮局的最小距离和为dp[i][j];

long s[M][M];                 //s[i][j]记录使用前i-1个邮局的村庄数

long euclidean[M][M];         //村庄i与村庄j间的欧式距离为euclidean[i][j]=euclidean[i][j-1]+|coordinate[j]-coordinate[i]|

long n, p, answer;

 

int Calculation(long i, long j)

{

       long k;

       //可以证明,当仅建立一个邮局时,最优解出现在中位数

       k = (i + j) / 2;

       return euclidean[k][j] - euclidean[k][i - 1];

}

 

int main()

{

       //freopen("1.txt", "r", stdin);

 

       int i, j, k;

       scanf("%ld%ld", &n, &p);

       for (i = 1; i <= n; i++)

       {

              scanf("%ld", &coordinate[i]);

       }

       memset(euclidean, 0, sizeof(euclidean));

       for (i = 1; i <= n; i++)

       {

              for (j = 1; j <= n; j++)

              {

                     euclidean[i][j] = euclidean[i][j - 1] + abs(coordinate[j] - coordinate[i]);

              }

       }

       memset(dp, 0, sizeof(dp));

       for (i = 1; i <= n; i++)

       {

              //计算在前i个村庄建立1个邮局的最小距离和

              dp[1][i] = Calculation(1, i);

       }

       for (i = 1; i <= n; i++)

       {

              //每个村庄建立一个邮局

              s[i][i] = i - 1;

       }

       for (i = 2; i <= p; i++)

       {

              j = n;

              dp[i][j] = inf;

              /*s[i-1][j]j-1的范围内枚举k,计算前k个村庄建立一个i-1个邮局、第k+1个村庄~j个村庄建立一个

              邮局的距离和.若该距离为目前最小,则记下方案.*/

              //由于决策量s[i][j]的最大值并不包含j=n的情况,所以这里在进行一次dp

              for (k = s[i - 1][j]; k <= j - 1; k++)

              {

                     int temp = dp[i - 1][k] + Calculation(k + 1, j);

                     if (temp

                     {

                            dp[i][j] = temp;

                            s[i][j] = k;

                     }

              }

              //按递减顺序枚举尾指针

              //决策量s[i][j]已经是缩短了搜索的范围

              for (j = n - 1; j >= i + 1; j--)

              {

                     dp[i][j] = inf;

                     /*s[i-1][j]s[i][j+1]的范围内枚举k,计算前k个村庄建立一个i-1个邮局、第k+1个村庄~j个村庄建立一个

                     邮局的距离和.若该距离为目前最小,则记下方案.*/

                     for (k = s[i - 1][j]; k <= s[i][j + 1]; k++)

                     {

                            int temp = dp[i - 1][k] + Calculation(k + 1, j);

                            if (temp

                            {

                                   dp[i][j] = temp;

                                   s[i][j] = k;

                            }

                     }

              }

       }

       printf("%d/n", dp[p][n]);

       return 0;

}

参考文献:《新篇实用算法分析与程序设计》                                  

 

 

 


推荐阅读
  • 本文详细介绍了在 Ubuntu 16.04 系统上安装和配置 PostgreSQL 数据库的方法,包括如何设置监听地址、启用密码加密、更改默认用户密码以及调整客户端访问控制。 ... [详细]
  • 在OpenCV 3.1.0中实现SIFT与SURF特征检测
    本文介绍如何在OpenCV 3.1.0版本中通过Python 2.7环境使用SIFT和SURF算法进行图像特征点检测。由于这些高级功能在OpenCV 3.0.0及更高版本中被移至额外的contrib模块,因此需要特别处理才能正常使用。 ... [详细]
  • Bootstrap Paginator 分页插件详解与应用
    本文深入探讨了Bootstrap Paginator这款流行的JavaScript分页插件,提供了详细的使用指南和示例代码,旨在帮助开发者更好地理解和利用该工具进行高效的数据展示。 ... [详细]
  • 深入理解云计算与大数据技术
    本文详细探讨了云计算与大数据技术的关键知识点,包括大数据处理平台、社会网络大数据、城市大数据、工业大数据、教育大数据、数据开放与共享的应用,以及搜索引擎与Web挖掘、推荐技术的研究及应用。文章还涵盖了云计算的基础概念、特点和服务类型分类。 ... [详细]
  • 实践指南:使用Express、Create React App与MongoDB搭建React开发环境
    本文详细介绍了如何利用Express、Create React App和MongoDB构建一个高效的React应用开发环境,旨在为开发者提供一套完整的解决方案,包括环境搭建、数据模拟及前后端交互。 ... [详细]
  • 本文旨在探讨设计模式在Visual FoxPro (VFP) 中的应用可能性。虽然VFP作为一种支持面向对象编程(xbase语言)的工具,其OO特性相对简明,缺乏高级语言如Java、C++等提供的复杂特性,但设计模式作为一种通用的解决方案框架,是否能有效应用于VFP,值得深入研究。 ... [详细]
  • Spring Boot使用AJAX从数据库读取数据异步刷新前端表格
      近期项目需要是实现一个通过筛选选取所需数据刷新表格的功能,因为表格只占页面的一小部分,不希望整个也页面都随之刷新,所以首先想到了使用AJAX来实现。  以下介绍解决方法(请忽视 ... [详细]
  • 在现代Web开发中,HTML5 Canvas常用于图像处理和绘图任务。本文将详细介绍如何将Canvas中的图像导出并上传至服务器,适用于拼图、图片编辑等场景。 ... [详细]
  • 电商高并发解决方案详解
    本文以京东为例,详细探讨了电商中常见的高并发解决方案,包括多级缓存和Nginx限流技术,旨在帮助读者更好地理解和应用这些技术。 ... [详细]
  • 本文详细介绍了PostgreSQL与MySQL在SQL语法上的主要区别,包括如何使用COALESCE替代IFNULL、金额格式化的方法、别名处理以及日期处理等关键点。 ... [详细]
  • 本文将从基础概念入手,详细探讨SpringMVC框架中DispatcherServlet如何通过HandlerMapping进行请求分发,以及其背后的源码实现细节。 ... [详细]
  • 深入理解:AJAX学习指南
    本文详细探讨了AJAX的基本概念、工作原理及其在现代Web开发中的应用,旨在为初学者提供全面的学习资料。 ... [详细]
  • 本文介绍了如何正确配置Ajax POST请求,以确保前端发送的数据能够被后端正确解析。重点在于前端JSON对象的键名需要与后端实体类的字段名严格匹配。 ... [详细]
  • 在尝试通过自定义端口部署Spring Cloud Eureka时遇到了连接失败的问题。本文详细描述了问题的现象,并提供了有效的解决方案,以帮助遇到类似情况的开发者。 ... [详细]
  • 在开发iOS应用时,面对不同状态(如数据加载成功、无数据、未登录、网络异常等)的界面管理,如何实现既高效又美观的用户体验?本文探讨了几种最佳实践方法。 ... [详细]
author-avatar
幸福蜗牛yeshi牛
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有