蜂窝小区最短距离实现 (数学归纳法+广度优先算法)

蜂窝地图研究 大概半年前在写蜂窝网格的A*寻路算法时,遇到了如何选择启发式的问题。传统的曼哈顿距离虽然可以正常运行找到正确的最短路径,但是在蜂窝网格地图中,两点间的最短路径不止一条,曼哈顿距离会使路径的选择总是偏向某一方向。根本原因是启发式中的曼哈顿距离并不是两点间真正的最短距离。在网上搜索了很多,但是一直没有搜到合适的方法,于是在炎热的某一天,自己动笔寻找这种方法。没想到的是答案竟然十分简单。下图采用二维坐标表 阅读详情

题目描述:

如图:由正六边形组成的蜂窝小区中,每个正六边形的编号也如图所示。求任意2点间的距离。(规定最大编号不超过100000)


分析:

1、求2点间的距离,第一印象就想到了广度优先算法(广度优先算法简单介绍:如图中的1点找编号为9的点时,可以第一次广度优先找到第二圈的所有元素,第二圈的元素再广度优先可以找到了9号点,所以必有一点可以从1点到9点,且距离为2)。但广度优先算法必须以知道任意点的相邻节点为前提。仔细观察又觉得点与点之间的关联又不是很有规律。

2、很容易看出6个点可以组成一个圆环,如:2,3,4,5,6,7    19,20,38,61,60,36等。为了找出规律,特按照编号顺序进行查找规律,那图看多了容易眼花,特意画了圆环虚线标识一个个圈,然后进行仔细分析;

3、得到所有点的相邻节点的前提是确定所有点的位置,然后再根据位置找规律得出其相邻的节点;


下面说下详细过程:

1、分析如何根据真实编号得到它所对应的圈号即圈内编号:


分析下每个圈的情况(以1号为1圈):

圈号容量最小编号最大编号
1111
2627
312819
4182037
图示1

1)发现从第2圈开始,元素数量呈等差趋势,依次增加6,容量规律即有:size(n)=6*(n-1) ,同时n>=2;

2)继续观察发现每圈的最小编号减去相邻内圈的最小编号刚好等于内圈的容量即有cycle(n,1)-cycle(n-1,1) = 6*(n-2),同时n>2(第2圈减第一圈规律不成立,n必须大于2),其中cycle(n,1)表示第n圈的第1个元素;

3)根据数列求和可知:

cycle(n,1)  -cycle(n-1,1)  =6*(n -    2)
cycle(n-1,1)-cycle(n-2,1)  =6*((n-1)- 2)
cycle(n-2,1)-cycle(n-3,1)  =6*((n-2)- 2)
……
cycle(3,1)  -cycle(2,1)    =6*((3)  - 2)
对以上等式分别左边与左边相加,右边与右边相加可知:cycle(n,1)-cycle(2,1)= 6*((3+4+…n)-(2*(n-2)))=6*((n-2)(n+3)/2-2*(n-2))= 6*(n-2)(n-1)/2=3(n-1)(n-2)

所以cycle(n,1)=cycle(2,1)+3(n-1)(n-2),由图示1可知cycle(2,1)=2;所以cycle(n,1)=2+3(n-1)(n-2),n>2;当n=2时,cycle(n,1)=2+3*(2-1)*(2-2)=2满足要求,所以cycle(n,1)=2+3(n-1)(n-2)的必需条件为n>=2;

3)由上可以推出:第n圈的m个元素可表示成:cycle(n,m)= 2+3(n-1)(n-2) -1+m,其中1<=m<6*(n-1)且n>=2,当n=1时,cycle(1,1)=1;

至此已经可以推出任意一个真实编号对应的圈号与圈内的编号了:

思路:对给定的任意真实编号与第n圈的极大值比较,若大于则取n+1圈继续比较,小于时停止比较,当前圈号为真实编号对应的圈号,根据cycle(n,m)公式可以计算出m值(圈内编号);


2、分析一个点与所有相邻点之间的关系(直接考虑n>=2的情况,n=1时可做特殊处理):

任意一个点在蜂窝小区中都有6个相邻节点,把它围在中间。

取第3圈的起始点8(第3圈的1号点)的相邻点进行分析,它有2个相邻点在其内圈上,2个点在当前圈,且在它左右;9号点(第3圈的第2点)则只有一个内圈节点,3个相邻外圈节点;

继续分析可知:第4圈的第1、2号点有2个内圈节点,第3号点只有一个内圈节点

……

继续拿第五圈的点进行分析……

可得出如下结论(以第n圈的圈内编号为m的点为例,n>2):

1),当m<n-1时,它有2个内圈节点,圈内编号分别为m-1,m当m=1时,m-1取最大圈内编号,它有2个外圈节点,其圈内编号为m,m+1;

2)当m%n-1等于0时,它只有一个圈内节点,其圈内编号为:m*(n-2)/(n-1),外圈编号为:n+m*n/(n-2),n+m*n/(n-2)+1,n+m*n/(n-2)+2;

3)当m>n-1且m%n-1不等于0时,它有2个圈内节点,其编号可参考比它小的、且有3个内圈节点、且最接近的点,根据偏移来计算,公式如下:

m1= (m-m%(n-1))*(n-3)/(n-1)+m%(n-1)-1,m2=m1+1,其外圈的圈内编号为:w1 = (n-1)+((m-m%(n-1))/(n-1)-1)*n+2+m%(n-1)-1,w2 = w1+1

……

不敢再想一遍了,肯定有优化的空间,欢迎给思路给建议……


思路就说到这了:)


说说实现:

1、定义Position类,根据输入的真实编号转换成对应的圈号及圈内编号,并提供找到所有相邻节点的方法;

2、定义蜂窝类Honeycomb,封装了计算蜂窝最短距离的入口及广度优先搜索算法;

3、辅助工具类HoneycombUtils,封装了几个推导出来的数列公式;

 

import java.util.HashSet;
import java.util.Set;

/**
 * <pre>
 * 蜂窝中的一个点
 * 
 * </pre>
 */
public class Position
{
    /**
     * 圈号
     */
    private int cycleNo;
    
    /**
     * 圈中的编号
     */
    private int columnNo;
    
    /**
     * 真实编号
     */
    private int realNum;
    
    public Position(int realNum)
    {
        this.realNum = realNum;
        transfer();
    }
    
    /**
     * <pre>
     * 获取其所有的6个相邻点
     * 
     * @return
     * </pre>
     */
    public Set<Position> getClosestPositions()
    {
        Set<Position> closestPositions = new HashSet<Position>();
        Position nextPosition = null;
        Position outerPosition = null;
        
        int outerCycleNo = getCycleNo() + 1;
        int outerRealNum = 0;
        
        // 第一圈没有内圈,只有外圈相邻点
        if (getCycleNo() == 1)
        {
            for (int i = 2; i <= 7; i++)
            {
                nextPosition = new Position(i);
                closestPositions.add(nextPosition);
            }
            
            return closestPositions;
        }
        
        Position innerPosition = null;
        int innerRealNum = 0;
        int innerCycleNo = getCycleNo() - 1;
        
        // 当前点的列号低于圈号减1时,它与2个相邻的内圈点相邻
        if (getColumnNo() < innerCycleNo)
        {
            // 表示取最后一列(列号最大的那个点)
            if (getColumnNo() == 1)
            {
                innerPosition = getMaxCyclePosition(innerCycleNo);
            }
            // 否则内圈列号取getColumnNo()-1
            else
            {
                innerRealNum = HoneycombUtils.getMinOfRealNumInCycle(innerCycleNo) - 1 + getColumnNo() - 1;
                innerPosition = new Position(innerRealNum);
            }
            closestPositions.add(innerPosition);
            
            // 添加另一个内圈相邻点
            innerRealNum = HoneycombUtils.getMinOfRealNumInCycle(innerCycleNo) - 1 + getColumnNo();
            innerPosition = new Position(innerRealNum);
            closestPositions.add(innerPosition);
            
            // 添加2个外圈相邻点
            outerRealNum = HoneycombUtils.getMinOfRealNumInCycle(outerCycleNo) - 1 + getColumnNo();
            outerPosition = new Position(outerRealNum);
            closestPositions.add(outerPosition);
            
            closestPositions.add(outerPosition.getNextPosition());
        }
        // 内环只有一个相邻点
        else if (getColumnNo() % innerCycleNo == 0)
        {
            if (innerCycleNo == 1)
            {
                innerPosition = new Position(1);
            }
            else
            {
                innerRealNum =
                    HoneycombUtils.getMinOfRealNumInCycle(innerCycleNo) - 1 + getColumnNo() * (innerCycleNo - 1)
                        / innerCycleNo;
                innerPosition = new Position(innerRealNum);
            }
            closestPositions.add(innerPosition);
            
            // 添加3个外圈相邻的点
            outerRealNum =
                HoneycombUtils.getMinOfRealNumInCycle(outerCycleNo) - 1 + innerCycleNo
                    + (getColumnNo() / innerCycleNo - 1) * getCycleNo();
            
            outerPosition = new Position(outerRealNum);
            closestPositions.add(outerPosition);
            
            nextPosition = outerPosition.getNextPosition();
            closestPositions.add(nextPosition);
            
            nextPosition = nextPosition.getNextPosition();
            closestPositions.add(nextPosition);
            
        }
        // 否则内环有2个相邻点
        else
        {
            // 找出同一圈中列号较小且只有一个相邻点的点
            int addColumnNo = getColumnNo() % innerCycleNo;
            int criticalColumnNo = getColumnNo() - addColumnNo;
            
            innerRealNum =
                HoneycombUtils.getMinOfRealNumInCycle(innerCycleNo) - 1 + criticalColumnNo * (innerCycleNo - 1)
                    / innerCycleNo + addColumnNo - 1;
            
            innerPosition = new Position(innerRealNum);
            closestPositions.add(innerPosition);
            
            closestPositions.add(innerPosition.getNextPosition());
            
            // 添加另一个外圈点
            outerRealNum =
                HoneycombUtils.getMinOfRealNumInCycle(outerCycleNo) - 1 + innerCycleNo
                    + (criticalColumnNo / innerCycleNo - 1) * getCycleNo() + 2 + addColumnNo - 1;
            
            outerPosition = new Position(outerRealNum);
            closestPositions.add(outerPosition);
            
            closestPositions.add(outerPosition.getNextPosition());
        }
        
        // 添加本圈中的2个与之相邻的点
        closestPositions.add(getLastPosition());
        closestPositions.add(getNextPosition());
        
        return closestPositions;
    }
    
    /**
     * 重载方法
     * 
     * @return
     */
    @Override
    public int hashCode()
    {
        final int prime = 31;
        int result = 1;
        result = prime * result + realNum;
        return result;
    }
    
    /**
     * 重载方法
     * 
     * @param obj
     * @return
     */
    @Override
    public boolean equals(Object obj)
    {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Position other = (Position)obj;
        if (realNum != other.realNum)
            return false;
        return true;
    }
    
    /**
     * 重载方法
     * 
     * @return
     */
    @Override
    public String toString()
    {
        return "Position [realNum=" + realNum + "]";
    }
    
    /**
     * <pre>
     * 把蜂窝上一个点的编号转换成圈号 + 圈内的编号
     * </pre>
     */
    private void transfer()
    {
        // 在第一圈
        if (getRealNum() == 1)
        {
            setCycleNo(1);
            setColumnNo(1);
        }
        // 在其它圈
        else
        {
            int cycle = 2;
            while (HoneycombUtils.getMaxOfRealNumInCycle(cycle) < getRealNum())
            {
                cycle++;
            }
            setCycleNo(cycle);
            
            // 计算真实编号对应圈中的编号
            int minCycleNum = HoneycombUtils.getMinOfRealNumInCycle(cycle);
            int columnNo = getRealNum() - minCycleNum + 1;
            setColumnNo(columnNo);
        }
    }
    
    /**
     * <pre>
     * 获取一圈中的下一个位置,如果是最后一个位置,下一个指向第一个;否则列号加1
     * 
     * @return
     * </pre>
     */
    private Position getNextPosition()
    {
        // 最后一个的下一个指向圈中的第一个
        if (getRealNum() == HoneycombUtils.getMaxOfRealNumInCycle(getCycleNo()))
        {
            return getMinCyclePosition();
        }
        else
        {
            return new Position(getRealNum() + 1);
        }
    }
    
    /**
     * <pre>
     * 获取同一圈中列号小1的点
     * 
     * @return
     * </pre>
     */
    private Position getLastPosition()
    {
        if (getRealNum() == HoneycombUtils.getMinOfRealNumInCycle(getCycleNo()))
        {
            return getMaxCyclePosition();
        }
        else
        {
            return new Position(getRealNum() - 1);
        }
    }
    
    /**
     * <pre>
     * 获取指定圈的最大列号对应的点
     * 
     * @param cycleNo
     * @return
     * </pre>
     */
    private Position getMaxCyclePosition(int cycleNo)
    {
        return new Position(HoneycombUtils.getMaxOfRealNumInCycle(cycleNo));
    }
    
    /**
     * <pre>
     * 获取当前圈的最大点
     * 
     * @return
     * </pre>
     */
    private Position getMaxCyclePosition()
    {
        return getMaxCyclePosition(getCycleNo());
    }
    
    /**
     * <pre>
     * 获取指定圈中最小列号对应的最小点
     * 
     * @return
     * </pre>
     */
    private Position getMinCyclePosition(int cycleNo)
    {
        return new Position(HoneycombUtils.getMinOfRealNumInCycle(cycleNo));
    }
    
    /**
     * <pre>
     * 获取当前圈的最小点
     * 
     * @return
     * </pre>
     */
    private Position getMinCyclePosition()
    {
        return getMinCyclePosition(getCycleNo());
    }
    
    /**
     * 获取 cycleNo
     * 
     * @return 返回 cycleNo
     */
    private int getCycleNo()
    {
        return cycleNo;
    }
    
    /**
     * 获取 columnNo
     * 
     * @return 返回 columnNo
     */
    private int getColumnNo()
    {
        return columnNo;
    }
    
    /**
     * 获取 realNum
     * 
     * @return 返回 realNum
     */
    private int getRealNum()
    {
        return realNum;
    }
    
    /**
     * 设置 cycleNo
     * 
     * @param 对cycleNo进行赋值
     */
    private void setCycleNo(int cycleNo)
    {
        this.cycleNo = cycleNo;
    }
    
    /**
     * 设置 columnNo
     * 
     * @param 对columnNo进行赋值
     */
    private void setColumnNo(int columnNo)
    {
        this.columnNo = columnNo;
    }
}


 

/**
 * <pre>
 * 蜂窝工具类
 * 
 * </pre>
 */
public final class HoneycombUtils
{
    
    /**
     * <默认构造函数>
     */
    private HoneycombUtils()
    {
    }
    
    /**
     * <pre>
     * 获取蜂窝一圈中的最大真实编号(圈号>=2)
     * 
     * @param cycleNo 圈号
     * @return
     * </pre>
     */
    public static int getMaxOfRealNumInCycle(int cycleNo)
    {
        return getMinOfRealNumInCycle(cycleNo) + getMaxColumnNumInCycle(cycleNo) - 1;
    }
    
    /**
     * <pre>
     * 获取蜂窝一圈中的最小真实编号
     * 
     * @param cycleNo 圈号
     * @return
     * </pre>
     */
    public static int getMinOfRealNumInCycle(int cycleNo)
    {
        return 2 + 3 * (cycleNo - 1) * (cycleNo - 2);
    }
    
    /**
     * <pre>
     * 获取一圈中的最大列号(圈号>=2)
     * 
     * @param cycleNo 圈号
     * @return
     * </pre>
     */
    public static int getMaxColumnNumInCycle(int cycleNo)
    {
        return 6 * (cycleNo - 1);
    }
}


 

import java.util.HashSet;
import java.util.Set;

/**
 * <pre>
 * 蜂窝
 * 
 * </pre>
 */
public final class Honeycomb
{
    private static int count;
    
    private static Set<Position> positions = new HashSet<Position>();
    
    private static Set<Position> closestPositions = new HashSet<Position>();
    
    private Honeycomb()
    {
    }
    
    /**
     * <pre>
     * 启动入口,获取蜂窝中2个点的距离
     * 
     * @param startPos 起始位置
     * @param endPos 查找目标位置
     * @return
     * </pre>
     */
    public static int getDistance(int startPos, int endPos)
    {
        if (!check(startPos) || !check(endPos))
        {
            return -1;
        }
        
        Position startPosition = new Position(Math.min(startPos, endPos));
        Position endPosition = new Position(Math.max(startPos, endPos));
        
        return getDistance(startPosition, endPosition);
    }
    
    private static boolean check(int pos)
    {
        if (pos <= 0 || pos > 100000)
        {
            return false;
        }
        return true;
    }
    
    /**
     * <pre>
     * 初始化
     * 
     * </pre>
     */
    private static void init()
    {
        positions.clear();
        count = 0;
        closestPositions.clear();
    }
    
    /**
     * <pre>
     * 封装成内部需要的入口
     * 
     * @param startPosition 起始点
     * @param endPosition 目标点
     * @return
     * </pre>
     */
    private static int getDistance(Position startPosition, Position endPosition)
    {
        init();
        closestPositions.add(startPosition);
        searchNext(endPosition);
        return count;
    }
    
    /**
     * <pre>
     * 广度优先遍历,每次取当前点的所有相邻点跟目标点比较,相等就退出,否则一直迭代查找
     * 
     * @param endPosition
     * </pre>
     */
    private static void searchNext(Position endPosition)
    {
        if (closestPositions.contains(endPosition))
        {
            return;
        }
        
        Set<Position> copyPositions = new HashSet<Position>(closestPositions.size());
        copyPositions.addAll(closestPositions);
        
        closestPositions.clear();
        
        for (Position closestPosition : copyPositions)
        {
            addClosestPositions(closestPosition.getClosestPositions());
        }
        
        count++;
        searchNext(endPosition);
    }
    
    private static void addClosestPositions(Set<Position> oneOfpositions)
    {
        for (Position position : oneOfpositions)
        {
            if (!positions.contains(position))
            {
                closestPositions.add(position);
            }
            
            positions.add(position);
        }
    }
}

测试类:

PositionTest:验证获取点的相邻节点是否正确:

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import java.util.Set;

import org.junit.Test;

/**
 * <pre>
 * <一句话功能简述>
 * 
 * </pre>
 */
public class PositionTest
{
    
    /**
     * case01:极限情况:第一圈的所有相邻节点是否正确
     */
    @Test
    public void testGetClosestPositions01()
    {
        Position pos = new Position(1);
        
        Set<Position> positions = pos.getClosestPositions();
        
        assertEquals(positions.size(), 6);
        
        for (int i = 2; i <= 7; i++)
        {
            assertTrue(positions.contains(new Position(i)));
        }
    }
    
    /**
     * case02:正常情况:第二圈的某点所有相邻节点是否正确
     */
    @Test
    public void testGetClosestPositions02()
    {
        Position pos = new Position(2);
        
        Set<Position> positions = pos.getClosestPositions();
        
        assertEquals(positions.size(), 6);
        
        assertTrue(positions.contains(new Position(1)));
        assertTrue(positions.contains(new Position(3)));
        assertTrue(positions.contains(new Position(7)));
        assertTrue(positions.contains(new Position(8)));
        assertTrue(positions.contains(new Position(9)));
        assertTrue(positions.contains(new Position(10)));
        
        pos = new Position(7);
        positions = pos.getClosestPositions();
        assertTrue(positions.contains(new Position(1)));
        assertTrue(positions.contains(new Position(2)));
        assertTrue(positions.contains(new Position(6)));
        assertTrue(positions.contains(new Position(8)));
        assertTrue(positions.contains(new Position(18)));
        assertTrue(positions.contains(new Position(19)));
        
        pos = new Position(6);
        positions = pos.getClosestPositions();
        assertTrue(positions.contains(new Position(1)));
        assertTrue(positions.contains(new Position(5)));
        assertTrue(positions.contains(new Position(7)));
        assertTrue(positions.contains(new Position(16)));
        assertTrue(positions.contains(new Position(17)));
        assertTrue(positions.contains(new Position(18)));
    }
    
    /**
     * case03:正常情况:第三圈的某点所有相邻节点是否正确
     */
    @Test
    public void testGetClosestPositions03()
    {
        Position pos = new Position(8);
        
        Set<Position> positions = pos.getClosestPositions();
        
        assertEquals(positions.size(), 6);
        
        assertTrue(positions.contains(new Position(2)));
        assertTrue(positions.contains(new Position(7)));
        assertTrue(positions.contains(new Position(9)));
        assertTrue(positions.contains(new Position(19)));
        assertTrue(positions.contains(new Position(20)));
        assertTrue(positions.contains(new Position(21)));
        
        pos = new Position(9);
        positions = pos.getClosestPositions();
        assertTrue(positions.contains(new Position(2)));
        assertTrue(positions.contains(new Position(8)));
        assertTrue(positions.contains(new Position(10)));
        assertTrue(positions.contains(new Position(21)));
        assertTrue(positions.contains(new Position(22)));
        assertTrue(positions.contains(new Position(23)));
        
        pos = new Position(11);
        positions = pos.getClosestPositions();
        assertTrue(positions.contains(new Position(3)));
        assertTrue(positions.contains(new Position(10)));
        assertTrue(positions.contains(new Position(12)));
        assertTrue(positions.contains(new Position(24)));
        assertTrue(positions.contains(new Position(25)));
        assertTrue(positions.contains(new Position(26)));
        
        pos = new Position(12);
        positions = pos.getClosestPositions();
        assertTrue(positions.contains(new Position(3)));
        assertTrue(positions.contains(new Position(4)));
        assertTrue(positions.contains(new Position(11)));
        assertTrue(positions.contains(new Position(13)));
        assertTrue(positions.contains(new Position(27)));
        assertTrue(positions.contains(new Position(26)));
        
        pos = new Position(19);
        positions = pos.getClosestPositions();
        assertTrue(positions.contains(new Position(7)));
        assertTrue(positions.contains(new Position(8)));
        assertTrue(positions.contains(new Position(18)));
        assertTrue(positions.contains(new Position(20)));
        assertTrue(positions.contains(new Position(36)));
        assertTrue(positions.contains(new Position(37)));
    }
    
    /**
     * case03:正常情况:第三圈的某点所有相邻节点是否正确
     */
    @Test
    public void testGetClosestPositions04()
    {
        Position pos = new Position(20);
        
        Set<Position> positions = pos.getClosestPositions();
        
        assertEquals(positions.size(), 6);
        
        assertTrue(positions.contains(new Position(8)));
        assertTrue(positions.contains(new Position(19)));
        assertTrue(positions.contains(new Position(21)));
        assertTrue(positions.contains(new Position(37)));
        assertTrue(positions.contains(new Position(38)));
        assertTrue(positions.contains(new Position(39)));
        
        pos = new Position(21);
        positions = pos.getClosestPositions();
        assertTrue(positions.contains(new Position(9)));
        assertTrue(positions.contains(new Position(8)));
        assertTrue(positions.contains(new Position(40)));
        assertTrue(positions.contains(new Position(20)));
        assertTrue(positions.contains(new Position(22)));
        assertTrue(positions.contains(new Position(39)));
        
        pos = new Position(25);
        positions = pos.getClosestPositions();
        assertTrue(positions.contains(new Position(11)));
        assertTrue(positions.contains(new Position(24)));
        assertTrue(positions.contains(new Position(26)));
        assertTrue(positions.contains(new Position(44)));
        assertTrue(positions.contains(new Position(45)));
        assertTrue(positions.contains(new Position(46)));
        
        pos = new Position(29);
        positions = pos.getClosestPositions();
        assertTrue(positions.contains(new Position(13)));
        assertTrue(positions.contains(new Position(14)));
        assertTrue(positions.contains(new Position(28)));
        assertTrue(positions.contains(new Position(30)));
        assertTrue(positions.contains(new Position(50)));
        assertTrue(positions.contains(new Position(51)));
        
        pos = new Position(37);
        positions = pos.getClosestPositions();
        assertTrue(positions.contains(new Position(19)));
        assertTrue(positions.contains(new Position(20)));
        assertTrue(positions.contains(new Position(36)));
        assertTrue(positions.contains(new Position(38)));
        assertTrue(positions.contains(new Position(60)));
        assertTrue(positions.contains(new Position(61)));
    }
}


HoneycombTest类,验证距离计算是否正确

import static org.junit.Assert.assertEquals;

import org.junit.Test;

/**
 * <pre>
 * <一句话功能简述>
 * 
 * </pre>
 */
public class HoneycombTest
{
    /**
     * <pre>
     * CASE01:参数非法
     * 
     * </pre>
     */
    @Test
    public void testGetDistance01()
    {
        assertEquals(Honeycomb.getDistance(1, 0), -1);
        assertEquals(Honeycomb.getDistance(-1, 1), -1);
        assertEquals(Honeycomb.getDistance(-1, -1), -1);
    }
    
    /**
     * <pre>
     * CASE02:临界值
     * 
     * </pre>
     */
    @Test
    public void testGetDistance02()
    {
        assertEquals(Honeycomb.getDistance(1, 1), 0);
        assertEquals(Honeycomb.getDistance(2, 2), 0);
    }
    
    /**
     * <pre>
     * CASE03:正常情况
     * 
     * </pre>
     */
    @Test
    public void testGetDistance03()
    {
        assertEquals(Honeycomb.getDistance(2, 40), 3);
        
        assertEquals(Honeycomb.getDistance(49, 61), 8);
        
        assertEquals(Honeycomb.getDistance(50, 44), 5);
        
        assertEquals(Honeycomb.getDistance(47, 59), 8);
        
        assertEquals(Honeycomb.getDistance(49, 57), 8);
        
        assertEquals(Honeycomb.getDistance(50, 44), 5);
        
        assertEquals(Honeycomb.getDistance(100000, 1), 183);
        
        assertEquals(Honeycomb.getDistance(100000, 88888), 355);
    }
}



 

 

 

 

 

蜂窝小区最短距离的坐标系解法 如下图所示,蜂窝小区,以1为中心,顺时针编号,编号最大限定为100000。求任意两编号之间的最短距离。两个相邻小区的距离为1 示例:19到30的最短距离为5 实现如下三个接口: /************************************************************************ Description  : 初始化蜂窝小区信息 Prototype 阅读详情

相关推荐

IT知识百科:什么是蜂窝小区?

蜂窝小区的基本结构由基站、小区边界和用户设备组成。基站是蜂窝小区的核心,负责发射和接收无线信号,同时协调小区内的通信。每个蜂窝小区之间存在一定的重叠区域,称为小区边界,这有助于确保用户在移动时平滑地切换到相邻小区。用户设备(如手机)通过与基站之间的通信实现与网络的连接。也称为无线电基站,是蜂窝小区的核心设备,负责管理小区内的通信。基站通过无线信号与用户设备进行通信,以提供数据传输和语音通话服务。是相邻蜂窝小区之间的过渡区域。

网络技术联盟站 1671

蜂巢(蓝桥杯python)

蓝桥杯杂题

nai_long的博客 1466

ArcGIS中生成蜂窝多边形算法解析

本文详细解析了在ArcGIS中生成蜂窝多边形的算法,并提供了相应的源代码示例。读者可以根据实际需求,在ArcGIS中使用Python编程语言并结合ArcPy库提供的功能,可以实现生成蜂窝多边形。生成蜂窝多边形:根据计算得到的蜂窝顶点坐标,可以使用ArcGIS中的多边形绘制函数来生成蜂窝多边形。多边形绘制函数需要输入顶点坐标的数组,并根据数组中的顺序连接各个顶点,形成闭合的多边形。可以通过给定的地理范围和网格大小来计算蜂窝的行数和列数,然后根据行列索引计算每个蜂窝的中心点坐标。

ObDjango的博客 320

python蜂窝状六边形_画多层六边形(小区),蜂窝状,matlab

作者:zfy,转载请注明画多层六边形,蜂窝状,第一个和第二个参数为最中心小区的横纵坐标,第三个参数为小区半径,第四个为所需画的层数(如果只画第一个六边形拿出程序中底下部分cirliu即可,只一个六边形视为第0层,该参数>=1)。我们通常需要它在一个矩形界面中显示,那么将蜂窝中心放在矩形中心,然后试着运行一个程序,看在半径为r的情况下几层能布满即可。%%%%%%%%%%%%%%%%%%%%%b...

weixin_39715652的博客 1454

【GA TSP】基于matlab遗传算法求解旅行商问题【含Matlab源码 1337期】

遗传算法求解旅行商问题 完整代码,直接运行,适合小白!可提供运行操作视频!

订阅付费专栏Matlab(奶茶价版),可赠送奶茶价版付费专栏指定代码1份; 1398

蜂窝最短距离

最短距离

java 蜂窝算法用于地图或者坐标系聚合计算

基于平面空间坐标系,或者是地图区域中,存在若干的散点数据,需要根据坐标系的比例或者是地图的比例大小,做空间的聚合,将多个散点聚合到一个点位中时,用到蜂窝网格的计算。

pjw1217的博客 1285

ST-Link V2的隐藏技能:多通道串口调试的终极指南

本文深入探讨了ST-Link V2的多通道串口调试功能,突破传统烧录工具的限制。通过详细的硬件配置、Arduino IDE设置和实战案例,展示了如何利用SWD接口实现多通道数据监控,提升STM32F103C8T6等开发板的调试效率。文章还提供了PCB布局优化和性能调优技巧,助力开发者充分发挥ST-Link V2的潜能。

weixin_29285605的博客 355

生成蜂窝网络图

有蜂窝网络如图,从1开始,按顺时针方向编号。要求给一个蜂窝数目N,得到整个蜂窝网络的图。 设每个节点周边的六个方向,按顺时针为 d1~d6。 思路就是根据当前的一个节点,要发展出下一个节点,那么下一个节点在当前节点的哪个方向上?经过分析,有如下3个规则: 规则1:以当前节点base为基础,按d1~d6方向发展新的节点。比如以1为基础,顺时针发展出2、3、4、5、6、7 在节点1的d6方向上

qyshooter的专栏 3174

数学建模 种群竞争模型 学习笔记

模型背景 应用场景 种群竞争模型 例如 s1=0.5,则表示对于供养甲的资源来讲,单位数量的乙的消耗为单位数量的甲的0.5倍,即表示乙对于该资源的占有能力是甲的0.5倍(即竞争力弱) 仿真结果及分析 (1)设置自然增长率 r1=r2=1 (2)改变自然增长率 r1=r2=0.3 (3)修改甲和乙的最大容量 n1=10000, n2=100 (4)修改甲和乙的初始数量 x1=10, x...

Test_tju的博客 2028

最小路径和——动态规划求解(Java实现)

最小路径和——动态规划求解(Java实现) 题目: 给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 说明:每次只能向下或者向右移动一步。 示例: 输入: [ [1,3,1], [1,5,1], [4,2,1] ] 输出: 7 解释: 因为路径 1→3→1→1→1 的总和最小。 这题和机器人走路的思路类似,就是状态方程有所不同,...

weixin_43395911的博客 894

蜂巢型六边形A星寻路算法unity完整流程

https://www.fgba.net/sitemap.xml

august5291的博客 2030

ethernet eth0: Could not attach to PHY

整个流程看下来就是MAC connect PHY的过程失败了,失败的具体原因根据config_init,上图(bcm54xx_config_init) ,从此方向入手去定位原因;我这里的问题是has_gmac4没有置1,根据 has_gmac4: uses GMAC4 core.按照上面的调用逻辑,添加了部分打印,定位到__phy_read接口返回失败。stmmac_mdio_read 大部分都是linux的标准接口。最终取决于平台用的是哪家的phy,调用config_init。

无线互联&网络介绍 2702

蜂窝小区的数学模型

设计模型: 1、  设计一个XY轴坐标系,1是原点,坐标(0,0) 2、  X轴:49、28、13、4、1、7、19、37、61的六边形中心所在直线(如图),1和7之间的距离是7,对应坐标轴的1个刻度 3、  Y轴:45、25、11、3、1、6、17、34、57 的六边形中心所在直线(如图),同样刻度是1 4、  从内向外都是有一个个圈(Cycle)组成,1是第0圈,2-7是第1圈,8-1

sinapme的专栏 6116

PentAGI自动渗透测试平台搭建与使用

但是PentAGI的缺陷也比较明显,一个是自动化程度高带来过程的介入困难,整个渗透的过程都交给AI自动决策,无法进行人工调整,耗时较长;从上述过程来看PentAGI似乎是一个比较“可用”的AI自动化渗透测试平台,但是在继续等待测试的过程中,PentAGI的一些缺点也暴露了出来,一个是测试的过程非常漫长,因为PentAGI是使用配置大模型API key的方式全自动运行,支持openai、deepseek等主流LLM大模型,过程中不需要人工介入,会不断自动调整,所以比较依赖于大模型本身的响应速度。

墨痕诉清风的博客 2403

【Agent实战】Agent Skills 深度解析:从原理到落地的完整指南

本文深入解析了Agent Skills的概念及其在AI协作中的实际应用。Skill是一种可被AI按需发现和加载的任务执行说明书,它将团队经验、规则和步骤固化为结构化文档,如SKILL.md。文章阐明了Skill与Prompt、MCP、Function Calling的关系,强调Skill专注于"怎么做"而非底层能力。重点介绍了SKILL.md的编写规范,包括元数据命名规则、描述技巧和正文内容优化,旨在帮助开发者高效构建可复用的知识资产,提升Agent的任务执行稳定性与专业性。通过清晰的示例和对比,为AI架构

少说,多做 115

【论文】利用移动性的比例公平蜂窝调度测量和算法

我们开发了利用移动性的预测有限视界PF调度框架。我们提供了来自3G网络的广泛信道测量结果,并表征了由移动性引起的信道状态趋势。我们发现用户的信道状态具有高度可重复性,并利用这一点开发了数据速率预测机制。然后,我们提出了一些利用预测机制的信道分配估计算法。我们的基于跟踪的模拟考虑了由预测和信道分配估计算法组合而成的框架实例。它们表明该框架可以将吞吐量提高15%到55%,与传统的PF调度器相比,同时提高了公平性。

unseven的博客 1517

基于Simscape的双PID比例调速阀与比例溢流阀液压控制系统建模与仿真

本文提出了一种基于Simscape的双PID液压控制系统建模方法,通过比例调速阀和比例溢流阀实现液压缸速度与压力的解耦控制。系统采用Simscape Fluids物理建模,精确模拟液压元件非线性特性。文章详细介绍了液压被控对象建模过程,包括动力单元、比例阀组合建模、执行机构及传感器配置。同时设计了双PID控制器架构,分别控制速度环和压力环,并给出参数整定建议。该方法通过物理网络直接模拟流体流动和压力动态,相比传统传递函数法具有更高精度,为液压系统仿真提供了有效解决方案。

AI的内部世界的博客 284

期末复习-移动通信

移动通信知识总结 参考资料: 1.哈尔滨工业大学(深圳)2021年春季《移动通信》课件 by 张霆廷 2.《Wireless Communications》by Andrea Goldsmith 3.《Wireless.Communications》by Andreas F. Molisch 4.《wireless communications:Principles and Practices》by Theodore S. Rappaport 导入优快云后图片比例有问题,但是我不想改了。 无线通信系统概述

weixin_43482424的博客 1万+

继电保护原理1.2-反时限过流保护

反时限过流保护

让你爱上电路设计 1万+

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

【无线通信】蜂窝系统——干扰与系统容量

语音信道中的干扰会导致串音,使得用户在通话时听到背景中的干扰声。控制信道中的干扰会导致丢失和阻塞通话,造成数字信号错误。城市地区的干扰更为严重,因为这些地区的RF噪声底座更高,并且基站和移动设备的数量更多。干扰被认为是增加容量的主要瓶颈,经常是掉话的原因。蜂窝系统产生的两种主要干扰是共信道干扰和邻信道干扰。尽管干扰信号通常是在蜂窝系统内部产生的,但在实际应用中很难控制(因为传播效应是随机的)。更难以控制的是外带用户产生的干扰,这种干扰没有预警,通常是由于用户设备的前端过载或间歇性互调产物引起的。

weixin_62403234的博客 1876

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

蓝桥杯2022年第十三届省赛真题蜂巢 python

问题描述 蜂巢由大量的六边形拼接而成,定义蜂巢中的方向为:0 表示正西方向,1 表示西偏北 60◦,2 表示东偏北 60◦,3 表示正东,4 表示东偏南 60◦,5 表示西偏南 60◦。 对于给定的一点 O,我们以 O 为原点定义坐标系,如果一个点 A 由 O 点先向 d 方向走 p 步再向 (d + 2) mod 6 方向(d 的顺时针 120◦ 方向)走 q 步到达,则这个点的坐标定义为 (d, p, q)。在蜂窝中,一个点的坐标可能有多种。 下图给出了点 B(0, 5, 3) 和点 C(2, 3, 2

weixin_48169169的博客 6564

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

LTE-M与NB-IoT蜂窝物联网

大规模、高速连接的部署需要大量带宽的支持。而蜂窝低功耗广域 (LPWA)技术为传感器和短数据突发交易设备在快速的、以 5G 为中心的技术世界中的不间断运行让路。长期演进机器类型通信 (LTE-M) 和窄带物联网 (NB-IoT)等移动物联网技术提供安全且经济高效的蜂窝 LPWA 功能。它们是未来全球 5G 集成和增长的催化剂,LTE-M 和 NB-IoT 将与 5G 网络共存。

Hern(宋兆恒) 1211

UVA 808 - Bee Breeding(建坐标系+找规律)

题目链接 https://cn.vjudge.net/problem/UVA-808 【题意】 给定两个格子的编号a和b(1<=a,b<=10000)求它们之间的最短距离 【思路】 太菜了,这种题根本没思路,看了别人的题解才会做. 大概是建立平面坐标系,一个x轴一个y轴,然后用向量表示每个点,向量位于一三象限时最短路为坐标绝对...

weixin_30940783的博客 291
上一篇: 网站的分布式架构
下一篇: HTTP协议详解
Johnny__Tang
博客等级 码龄18年 9粉丝 11原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值