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:深度优先搜索
动态规划算法
大问题拆分成小问题,小问题计算结果存储,下次直接用
朴素贝叶斯