问题描述
建筑(AABB相同)之间可以相交,建筑与城堡(AABB包围盒大于建筑)之间可以相交(包含建筑在城堡中的情况),建筑(AABB相同)之间可以相交,建筑与城堡(AABB包围盒大于建筑)之间可以相交(建筑在城堡中),如果建筑A满足一下情况视为建筑可用:
1.建筑A直接与城堡B相交
2.建筑A1直接与建筑A2相交,A2与A3相交... 建筑An与城堡
算法设计
把建筑和城堡抽象成有向有环图中的一个个节点Node,如果节点N1与邻近建筑(或城堡)N2相交,则加上N1->N2和N2<-N1两条边。如果某个建筑节点到任意一个城堡节点的连通路径都不存在,
我们称之为孤悬节点,标识0;否则可用标识1.
erlang 的digraph 模块满足本算法中对于图的需求。另外我们需要借助四叉树(或者九宫格)用来做相交检测。主要关注节点的插入和删除造成的状态改变。
节点插入:
I 如果待插入节点没有相交节点,插入节点,设置标识插入节点标识0
II 如果待插入节点是城堡节点,有相交节点且标识都为1,插入节点和边,设置标识插入节点标识0
III 如果待插入节点是城堡节点,有相交节点且标识不都为1,插入节点和边,设置标识插入节点标识0。
递归设置标识不为1的相交节点(城堡节点除外)标识为1.递归的截至条件遇到节点标识为1,或者城堡节点。
IV 如果与待插入节点相交的节点标识都是1,插入节点和边,设置插入节点的标识为1
V 如果与待插入节点相交的节点(不包含城堡节点)标识都是0,插入节点和边,插入节点的标识为0
VI 如果与待插入节点相交的节点标识都为0,同时插入节点又与城堡节点相交,插入节点和边,插入节点标识设为1。递归设置相交节点(城堡节点除外)的标识1,
递归的截至条件遇到节点标识为1,或者城堡节点。
VII 如果与待插入节点的相交的节点标识不都为1,插入节点和边,设置插入节点标识1。递归设置标识不为1的相交节点(城堡节点除外)标识为1,
递归的截至条件遇到节点标识为1,或者城堡节点。
节点删除:
I. 如果待删除节点没有相交节点,直接删除
II.如果待删除节点标识为0,删除。递归设置相交节点的标识为0,递归的截至条件遇到节点标识为0
III. 如果待删除节点标识为1且如果相交节点都不是孤悬节点,直接删除。
III. 如果待删除节点标识为1且如果相交节点有孤悬节点,直接删除。递归设置孤悬节点的标识为0,递归的截至条件遇到节点标识为0
测试用例(删除节点)
// 1,20节点是城堡节点
// 节点孤立意味着节点到任一城堡的没有连通路径
D = digraph:new().
[digraph:add_vertex(D,N) || N <- lists:seq(1, 24)].
[digraph:add_edge(D, V1, V2) || {V1, V2} <-[{1,2},{2,1},{2,3},{3,2},{1,4},{4,1},{4,5},{5,4}, {5,6},{6,5},{3,6},{6,3},{3,7},{7,3},{7,8},{8,7},{8,9},{9,8},{8,10},{10,8},{9,12},{12,9},{12,13},{13,12}, {10,11},{11,10},{11,13},{13,11},{10,15},{15,10},{15,16},{16,15},{16,17},{17,16},{17,20},{20,17}, {16,18},{18,16},{18,21},{21,18},{21,23},{23,21},{13,22},{22,13},{22,24},{24,22}]].
//删除节点7
digraph:del_vertex(D,7).
//判断节点3和8是否孤悬节点
lists:all(fun(E)-> digraph:get_short_path(D, 3, E)=:= false end, [1,20]).
lists:all(fun(E)-> digraph:get_short_path(D, 8, E)=:= false end, [1,20]).
3和8都不是孤悬节点,不需要继续处理
//删除节点13
digraph:del_vertex(D,13).
//判断节点11、12、22是否孤悬节点
lists:all(fun(E)-> digraph:get_short_path(D, 11, E)=:= false end, [1,20]).
lists:all(fun(E)-> digraph:get_short_path(D, 12, E)=:= false end, [1,20]).
lists:all(fun(E)-> digraph:get_short_path(D, 22, E)=:= false end, [1,20]).
//节点22孤立,递归获取相连的节点,并设置状态为0.递归的截至条件遇到节点标识为0