The scientist builds in order to study,
the engineer studies in order to build.
-- Fred Brooks

最近在忙各种毕业事项之余,一直在努力搞 Real-time GI ,可惜时间总是显得如此的不够用,搞完了 RSM 却忘了做 SRM,哈哈。为了避免长时间不思考算法问题,导致智商下降,决定弄个小问题来做一下。这个问题也是在搞 GI 的时候想到的,该问题的二维版本跟 GI 也算是有那么一丁点关系,尽管从原则上来说只用一个高度场来表示场景的话显然丢失了太多信息。

前面都是废话,现在正式开始,问题是这样的:

1-Dimensional Heightfield Visibility Query Problem

给定一个一维的高度场,可用数组 H 来表示,其中第 i 个元素 H[i] 代表点 i 处的高度,判断其中任意两点是否相互可见?

比如,若 H = {1, 0, 2, 2, 1, 3, 1, 0},根据 H 可以绘制出一个轮廓如图 1 所示:

      图1:1维高度场示意图

我们想查询任意两个点 i, j 是否相互可见(用 visible(i, j) 来表示,另外在后文中均假设 i <= j)。比如,在图1中有 visible(2, 5) = true(见图中绿色虚线),而 visible(3, 6) = false(见图中红色虚线)。

这个问题说简单也简单,因为若要查询 visible(i, j),只需要顺序从 H[i] 扫描到 H[j] ,判断一下斜率即可。这样每次查询的时间复杂度为 O(n)。

但是我们希望能做得更好,最好是能设计一个 online algorithm,先对 H 进行一下预处理,然后将每次查询的时间降为 O(1)。这当然可以做到,因为很明显我们可以预先将所有的 visible(i, j) 计算好并存储起来,这样的话需要 O(n^2) 的预处理时间,O(1) 的查询时间,同时需要 O(n^2) 的存储空间,为方便我们采用这样一种方式 <O(n^2), O(1) | O(n^2)> 来表示其复杂度。然而,当 n 较大时,这里 O(n^2) 的空间需求是不太能够接受的,如果你有过设计 online algorithm 的经验,此时的第一个想法可能会是看看能不能将空间复杂度降为 O(nlogn),同时仍然维持 O(1) 的查询时间。

幸运的是,这的确是可能的,采用常规的 sparse table 就可以做到。当然,这里对 sparse table 的处理与经典的 RMQ 问题稍有差别,因为这里需要建立两个 sparse table。其基本动机基于以下观察:

定理1:对于任意一个点对 (i, j),以及任意的另外两个点 k1, k2 位于 i, j 之间,且满足 k1 >= k2 – 1。若用 partial(i, k, j) 来表示点 i 在经过 i 到 k 之间的所有点后是否还能看到点 j(意思是不考虑 k+1 到 j 之间的点是否构成遮挡),于是有:

visible(i, j) 当且仅当 partial(i, k1, j) 且 partial(j, k2, i)。

定理1的证明很简单,在这里略过。事实上只要你想到它,那么它几乎就是不证自明的。若设 slope(i, k) 为点 i 在经过 i 到 k 之间的所有点后的最小未被遮挡斜率,那么只要知道 slop(i, k) 就能在 O(1) 时间内计算出 partial(i, k, j)。这个事实再加上定理1就构成了使用 sparse table 的基础:

1. sparse table 的预计算过程

对于每个点 i, 计算并存储 slope(i, i + 1), slope(i, i + 2), slope(i, i + 4), slope(i, i + 8), …. 以及 slope(i, i – 1), slope(i, i – 2), slope(i, i – 4), slope(i, i – 8)….

2. 查询过程

若要查询 visible(i, j), 先计算出 k = 2^( floor(log2( j - i) ), 即不大于 j – i 的最大2幂。然后从 sparse table 中查得 slope(i, i + k), slop(j, j – k),计算出 partial(i, i + k, j) 和 partial(j, j – k, i),从而得到 visible(i, j)。整个查询过程的时间复杂度为 O(1).

很遗憾在这里对 sparse table 的构造并不能像 RMQ 那样做到 O(nlogn),如果直接暴力搞的话需要 O(n^2) 的时间,使得整个 online algorithm 的复杂度为 <O(n^2), O(1) | O(nlogn)>。所幸,通过一些简单的优化,可以大幅度的提高建立 sparse table 的效率,经过我测试的数千组数据表明,优化后的算法的期望复杂度很有可能是 <O(nlognlogn, O(1) | O(nlogn)>,但我并没有进行详细的分析,因为对于这个问题很难去假定其输入应该满足什么样的分布条件。在我所使用测试的数据中,每个点的高度值都是互相独立的随机数,这在直观上其实并不符合现实。

优化的方法说起来很麻烦,懒得讲了,感兴趣的可以在直接看源代码。

如果不是要求查询时间一定为O(1),那么下面这个方法也可能行得通。先建立一个 cartesian tree, 然后通过 LCA 来搞,对于两个点 (i, j),若 LCA(i, j) != i && LAC(i, j) != j,那么直接就可以返回 visible(i, j) = false. 否则若某个点是另一个点的祖先,比如 j 是 i 的祖先,那么可以在树中从 i 遍历到 j 来进行判断。中间也可以根据凸性建立一些额外的连接来进行优化。这样预处理时间和空间都为 O(n) ,查询时间最坏也为 O(n),但大多数情况下应该非常快,因为 cartesian tree 的期望高度是 O(logn) 的,何况还有一堆优化手段可以搞,比如可以利用凸性建立一些额外的连接等等。哈,以后有时间再来尝试一下。

如果有人想到更好的方法,欢迎讨论…

转载于:https://www.cnblogs.com/atyuwen/archive/2011/03/09/visibility_query.html

1-Dimensional Heightfield Visibility Query相关推荐

  1. Hierarchical Z-Buffer Visibility (Hi-Z)

    可见性算法的目的是丢弃隐藏面, 对于GPU可以节省CPU传入顶点信息的带宽&顶点ALU&Fragment ALU的消耗, 对于CPU可以减少DC(物件被剔除了) 有三种方式可以实现可见 ...

  2. Using GDB To Trace Into a Parallel Worker Spawned By Postmaster During a Large Query

    1. Introduction 我正在研究一个新的PostgreSQL特性,它重新定义了确定元组可见性状态的方式.在我开始执行一个大型SELECT查询之前,这个特性工作得很好,这会触发PostgreS ...

  3. 计算广告(4)----query意图识别

    目录: 一.简介: 1.用户意图识别概念 2.用户意图识别难点 3.用户意图识别分类 4.意图识别方法: (1)基于规则 (2)基于穷举 (3)基于分类模型 二.意图识别具体做法: 1.数据集 2.数 ...

  4. Dimensional Modeling

    一.General 1. Concept DM / Dimensional Modeling / 维度模型 The process and outcome of designing logical d ...

  5. 使用JPA进行Update操作 @Query注解的用法,JPL

    使用jpa进行update操作有两种,第一种就是先查询,set,再进行save更新.这种做法过于繁杂,我只是要进行一个更新操作却变成了三步,所以我推荐使用第二种: @Modifying @Query( ...

  6. Retrofit 网络请求参数注解@Path @Field @Query 等使用

    请求参数呢大致如下,到个别人的图, 下面就说下这些内容使用 其中 @Path.@Query.@QueryMap 使用 Get 请求 , 加入使用了Post 请求注解使用@Path  一般都会是项目崩溃 ...

  7. mysql query browswer_MySQL数据库新特性之存储过程入门教程

    MySQL数据库新特性之存储过程入门教程 在MySQL 5中,终于引入了存储过程这一新特性,这将大大增强MYSQL的数据库处理能力.在本文中将指导读者快速掌握MySQL 5的存储过程的基本知识,带领用 ...

  8. android contentresolver权限,求助关于getcontentresolver().query()

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 今天搞了一天,用getcontentresolver().query()l来获取音乐列表,却啥也没有,是不是需要什么权限啊,代码如下,请大神帮帮忙啊. p ...

  9. Linux下__attribute__((visibility (default)))的使用

    在Linux下动态库(.so)中,通过GCC的C++ visibility属性可以控制共享文件导出符号.在GCC 4.0及以上版本中,有个visibility属性,可见属性可以应用到函数.变量.模板以 ...

最新文章

  1. Science子刊带来新遗传证据:早期人类驯化了自己
  2. ▼▲Delphi面向对象编程的20条规则
  3. 一文带你快速读懂.NET CLI
  4. TensorFlow 2.x GPU版在conda虚拟环境下安装步骤
  5. 你不知道你不懂javascript
  6. mysql 数字序列_MySQL中的数字序列
  7. android中json解析及使用 (下)
  8. 读书笔记 - 《漫威宇宙》
  9. 下载外网资源慢的解决办法
  10. 下列关于linux扩展名说法错误的是,全国计算机一级考试选择题集锦(2015年1月)
  11. 各种动漫情侣姿势的画法
  12. 网络运维系列:网络出口IP地址查询
  13. ArcGIS API for JavaScript开发之必学渲染方式及渲染符号概念(0)
  14. 微信群发提示频繁怎么办?
  15. 知识管理在企业竞争发展中的作用
  16. kalilinux链接蓝牙音响_怎么用手机蓝牙连接音响
  17. Linux如何实现网络通信
  18. 超详细的JavaScript对象分享,看完就会了
  19. 天地人“三界传说”官网基础效果(适合各分辨率页面)
  20. 传统企业如何电子商务

热门文章

  1. C语言 | C编程练习题(代码版)
  2. Matlab | Matlab从入门到放弃(6)——数组
  3. rust(68)-rust enum
  4. 【数据分析】年轻人如何才能实现年薪百万呢?
  5. 线性代数回顾.pptx
  6. 【深度学习】实战深度学习检测疟疾
  7. 【职场】你做程序员,真的是因为热爱吗?
  8. 网易云音乐:基于分布式图学习的推荐系统优化之路
  9. 【深度学习】深度学习两大基础Tricks:Dropout和BN详解
  10. 【Python基础】Python画王者荣耀英雄能力雷达图