A*,点的问题

大概能想到哪些写上哪些吧

1.unity寻路(navigation)

  NavMesh :可运行的表面自动生成的

  Navmesh Agent:寻路人物挂在的

  Off-Mesh Link:跳跃的

  NavmeshObstacle:不可通行地方

2.Dijkstra寻路算法

Dijkstra算法的目的在于找到从O点开始到其他各点的最短路径。

假设起点为A,从表里查找距离A最近的点(假设找到了B,添加到已经寻找的点),然后更新A->C的距离(用A->B->C代替),然后再选其次最近点的距离

选取起点,然后查找距离起点距离最短的点

using System;
using System.Collections;
using System.Text;
namespace DijkstraMethod
{
    class Program
    {
        //V1到V7的邻接矩阵
        static int[, ] Metro = new int[7, 7]{
        { 0, 3, 7, 5,2048,2048,2048},
        { 3, 0, 2,2048, 6,2048,2048},
        { 7, 2, 0, 3, 3,2048,2048},
        { 5,2048, 3, 0,2048, 2, 8},
        {2048, 6, 3,2048, 0,2048, 2},
        {2048,2048,2048, 2,2048, 0, 2},
        {2048,2048,2048, 8, 2, 2, 0} };
        static int row = 7;
        ArrayList S = new ArrayList();//S储存确定最短路径的顶点的下标
        ArrayList U = new ArrayList();//U中存储尚未确定路径的顶点的下标
        int[] distance = new int[7];//用以每次查询存放数据
        int[] prev = new int[7];//用以存储前一个最近顶点的下标
        bool[] Isfor = new bool[7]{ false, false, false, false, false, false, false };
        /// <summary>
        /// dijkstra算法的实现部分
        /// </summary>
        /// <param name="Start"></param>
        void FindWay(int Start)
        {
            S.Add(Start);
            Isfor[Start] = true;
            for (int i = 0; i < row; i++)
            {
                if (i != Start)
                    U.Add(i);
            }
            for (int i = 0; i < row; i++) {
                distance[i] = Metro[Start, i];
                prev[i] = 0;
            }
            int Count = U.Count;
            while (Count > 0)
            {
                int min_index = (int)U[0];//假设U中第一个数存储的是最小的数的下标
                foreach(int r in U)
                {
                    if (distance[r] < distance[min_index] && !Isfor[r])
                        min_index = r;
                }
                S.Add(min_index);//S加入这个最近的点
                Isfor[min_index] = true;
                U.Remove(min_index);//U中移除这个点;
                foreach(int r in U)
                {
                    //查找下一行邻接矩阵,如何距离和上一个起点的距离和与数组存储的相比比较小,就更改新的距离和起始点,再比对新的起点到各边的距离
                    if (distance[r] > distance[min_index] + Metro[min_index, r])
                    {
                        distance[r] = distance[min_index] + Metro[min_index, r];
                        prev[r] = min_index;
                    }
                    else
                    {
                        distance[r] = distance[r];
                    }
                }
                Count = U.Count;
            }
        }
        /// <summary>
        /// 把生成数据显示出来
        /// </summary>
        void display()
        {
            for (int i = 0; i < row; i++)
            {
                Console.Write("V1到V{0}的最短路径为→V1", i);
                int prePoint = prev[i];
                string s = "";
                StringBuilder sb = new StringBuilder(10);
                while (prePoint > 0)
                {
                    s = (prePoint + 1) + s;
                    prePoint = prev[prePoint];
                }
                for (int j = 0; j < s.Length; j++)
                {
                    sb.Append("-V").Append(s[j]);
                }
                Console.Write(sb.ToString());
                Console.Write("-V{0}", i);
                Console.WriteLine(":{0}", distance[i]);

            }
        }
        static void Main(string[] args)
        {
            Program p = new Program();
            p.FindWay(0);
            p.display();
            Console.ReadKey();
        }
    }
}

3.A*寻路(这个是最常问的)

public enum CompassDirections
{
    NotSet = 0,
    North = 1, //UP
    NorthEast = 2, //UP Right
    East = 3,
    SouthEast = 4,
    South = 5,
    SouthWest = 6,
    West = 7,
    NorthWest = 8
}

public class SecenePoint
{
    protected int m_posX;
    public int PosX
    {
        get
        {
            return m_posX;
        }
        set
        {
            m_posX = value;
        }
    }
    protected int m_posY;
    public int PosY
    {
        get
        {
            return m_posY;
        }
        set
        {
            m_posY = value;
        }
    }
    public SecenePoint(int x, int y)
    {
        m_posX = x;
        m_posY = y;
    }
}

public interface ICostGetter
{
    int GetCost(SecenePoint currentNodeLoaction, CompassDirections moveDirection);
}
public class SimpleCostGetter : ICostGetter
{
    public int GetCost(SecenePoint currentNodeLoaction, CompassDirections moveDirection)
    {
        if (moveDirection == CompassDirections.NotSet)
        {
            return 0;
        }

        if (moveDirection == CompassDirections.East || moveDirection == CompassDirections.West || moveDirection == CompassDirections.South || moveDirection == CompassDirections.North)
        {
            return 10;
        }

        return 14;
    }
}

public class AStartPoint
{
    public AStartPoint(SecenePoint loc, AStartPoint previous, int _costG, int _costH)
    {
        this.location = loc;
        this.previousNode = previous;
        this.costG = _costG;
        this.costH = _costH;
    }

    private SecenePoint location = new SecenePoint(0, 0);
    public SecenePoint Location
    {
        get { return location; }
    }
    private AStartPoint previousNode = null;
    public AStartPoint PreviousNode
    {
        get { return previousNode; }
    }
    public int CostF
    {
        get
        {
            return this.costG + this.costH;
        }
    }

    private int costG = 0;
    public int CostG
    {
        get { return costG; }
        set { costG = value; }
    }

    private int costH = 0;
    public int CostH
    {
        get { return costH; }
    }
    public void ResetPreviousNode(AStartPoint previous, int _costG)
    {
        this.previousNode = previous;
        this.costG = _costG;
    }
}


public class SceneMap
{
    private int lineCount = 10;   //反映地图高度,对应Y坐标
    private int columnCount = 10; //反映地图宽度,对应X坐标
    private SecenePoint[,] m_scenePoint;
    private bool[,] m_obstrale;
    private ICostGetter costGetter;
    private static List<CompassDirections> AllCompassDirections = new List<CompassDirections>();
    private void CompassDirectionsHelper()
    {
        AllCompassDirections.Add(CompassDirections.East);
        AllCompassDirections.Add(CompassDirections.West);
        AllCompassDirections.Add(CompassDirections.South);
        AllCompassDirections.Add(CompassDirections.North);
        AllCompassDirections.Add(CompassDirections.SouthEast);
        AllCompassDirections.Add(CompassDirections.SouthWest);
        AllCompassDirections.Add(CompassDirections.NorthEast);
        AllCompassDirections.Add(CompassDirections.NorthWest);
    }

    public SecenePoint GetAdjacentPoint(SecenePoint current, CompassDirections direction)
    {
        switch (direction)
        {
            case CompassDirections.North:
                {
                    return new SecenePoint(current.PosX, current.PosY - 1);
                }
            case CompassDirections.South:
                {
                    return new SecenePoint(current.PosX, current.PosY + 1);
                }
            case CompassDirections.East:
                {
                    return new SecenePoint(current.PosX+ 1, current.PosY);
                }
            case CompassDirections.West:
                {
                    return new SecenePoint(current.PosX- 1, current.PosY);
                }
            case CompassDirections.NorthEast:
                {
                    return new SecenePoint(current.PosX+ 1, current.PosY - 1);
                }
            case CompassDirections.NorthWest:
                {
                    return new SecenePoint(current.PosX- 1, current.PosY - 1);
                }
            case CompassDirections.SouthEast:
                {
                    return new SecenePoint(current.PosX + 1, current.PosY + 1);
                }
            case CompassDirections.SouthWest:
                {
                    return new SecenePoint(current.PosX- 1, current.PosY + 1);
                }
            default:
                {
                    return current;
                }
        }
    }

    //这里简单初始化,实际应该从配置中读取
    public void Init(int line,int column)
    {
        lineCount = line;
        columnCount = column;
        m_scenePoint = new SecenePoint[lineCount, columnCount];
        m_obstrale = new bool[lineCount, columnCount];
        for (int i = 0; i < lineCount; i++)
        {
            for (int j = 0; j < columnCount; j++)
            {
                m_scenePoint[i, j] = new SecenePoint(i,j);
                m_obstrale[i, j] = false;
            }
        }
        //这里也临时写的
        costGetter = new SimpleCostGetter();
        CompassDirectionsHelper();
    }
    //设置阻碍物
    public void SetObstrale(List<SecenePoint> obsList)
    {
        for (int i = 0; i < obsList.Count; i++)
        {
            m_obstrale[obsList[i].PosX, obsList[i].PosY] = true;
        }
    }

    private bool Contain(SecenePoint _point)
    {
        if(_point.PosX<0 || _point.PosX> lineCount|| _point.PosY < 0 || _point.PosY > columnCount)
        {
            return false;
        }
        return true;
    }
    /// AStarRoutePlanner A*路径规划。每个单元格Cell的位置用Point表示
    /// F = G + H 。
    /// G = 从起点A,沿着产生的路径,移动到网格上指定方格的移动耗费。
    /// H = 从网格上那个方格移动到终点B的预估移动耗费。使用曼哈顿方法,它计算从当前格到目的格之间水平和垂直的方格的数量总和,忽略对角线方向。
    private List<AStartPoint> closedList = new List<AStartPoint>();
    private List<AStartPoint> openedList = new List<AStartPoint>();
    private SecenePoint m_destination;
    public List<SecenePoint> Plan(SecenePoint start, SecenePoint destination)
    {
        if ((!Contain(start)) || (!Contain(destination)))
        {
            return new List<SecenePoint>();
        }
        m_destination = destination;
        AStartPoint startNode = new AStartPoint(start, null, 0, 0);
        openedList.Add(startNode);
        AStartPoint currenNode = startNode;
        //从起始节点开始进行递归调用
        return DoPlan(currenNode);
    }

    private List<SecenePoint> DoPlan(AStartPoint currenNode)
    {
        for (int i = 0; i < AllCompassDirections.Count; i++)
        {
            SecenePoint temp = GetAdjacentPoint(currenNode.Location, AllCompassDirections[i]);
            if (!Contain(temp)) //相邻点已经在地图之外
            {
                continue;
            }

            if (this.m_obstrale[temp.PosX, temp.PosY]) //下一个Cell为障碍物
            {
                continue;
            }
            int costG = this.costGetter.GetCost(currenNode.Location, AllCompassDirections[i]);
            int costH = Mathf.Abs(temp.PosX - m_destination.PosX) + Mathf.Abs(temp.PosY - m_destination.PosY);
            if(costH == 0)
            {
                List<SecenePoint> route = new List<SecenePoint>();
                route.Add(m_destination);
                route.Add(currenNode.Location);
                AStartPoint tempNode = currenNode;
                while (tempNode.PreviousNode != null)
                {
                    route.Add(currenNode.PreviousNode.Location);
                    tempNode = tempNode.PreviousNode;
                }
                route.Reverse();
                return route;
            }
            bool exit = false;
            for (int j = 0; j < closedList.Count; j++)
            {
                if(closedList[j].Location == temp&& closedList[j].CostG> costG)
                {
                    closedList[j].CostG = costG;
                    exit = true;
                }
            }
            for (int j = 0; j < openedList.Count; j++)
            {
                if (openedList[j].Location == temp && openedList[j].CostG > costG)
                {
                    openedList[j].CostG = costG;
                    exit = true;
                }
            }
            if (!exit)
            {
                openedList.Add(new AStartPoint(temp, currenNode, costG, costH));
            }
        }
        //将已遍历过的节点从开放列表转移到关闭列表
        openedList.Remove(currenNode);
        closedList.Add(currenNode);
        //能遍历的都完事了
        if(openedList.Count == 0)
        {
            return null;
        }
        AStartPoint target = openedList[0];
        for (int j = 0; j < openedList.Count; j++)
        {
            if (openedList[j].CostF < target.CostF)
            {
                target = openedList[j];
            }
        }
        //对开放列表中的下一个代价最小的节点作递归调用
        return this.DoPlan(target);
    }
}

 4.点是否在多边形范围内

一般是点做平行或者竖直的有方向的线看跟多边形的交点个数,奇数在里面,偶数在外面

代码判定

using UnityEngine;
using System.Collections.Generic;

public class MathTool {

    /// <summary>
    /// 点是否在多边形范围内
    /// </summary>
    /// <param name="p"></param>
    /// <param name="vertexs">多边形顶点列表</param>
    /// <returns></returns>
    public static bool IsPointInPolygon(Vector2 p, List<Vector2> vertexs)
    {
        int crossNum = 0;
        int vertexCount = vertexs.Count;

        for (int i = 0; i < vertexCount; i++)
        {
            Vector2 v1 = vertexs[i];
            Vector2 v2 = vertexs[(i + 1) % vertexCount];

            if (((v1.y <= p.y) && (v2.y > p.y))
                || ((v1.y > p.y) && (v2.y <= p.y)))
            {
                if (p.x < v1.x + (p.y - v1.y) / (v2.y - v1.y) * (v2.x - v1.x))
                {
                    crossNum += 1;
                }
            }
        }

        if (crossNum % 2 == 0)
        {
            return false;
        }
        else
        {
            return true;
        }
    }
}

bfprt算法解析

bfprt解法:

bfprt解法和常规解法唯一不同的就是在number的选取上,其他地方一模一样,所以我们只讲选取number这一过程。

第一步:我们将数组每5个相邻的数分成一组,后面的数如果不够5个数也分成一组。

第二步:对于每组数,我们找出这5个数的中位数,将所有组的中位数构成一个median数组(中位数数组)。

第三步:我们再求这个中位数数组中的中位数,此时所求出的中位数就是那个number。

第四步:通过这个number进行partation过程,下面和常规解法就一样了。

BFS和DFS

BFS:广度优先搜索

DFS:深度优先搜索

动态规划算法

大问题拆分成小问题,小问题计算结果存储,下次直接用

朴素贝叶斯

posted @ 2020-10-20 16:43  Elijah_j  阅读(118)  评论(0编辑  收藏  举报